diff --git a/AUTHORS b/AUTHORS index a2acf1a..a5ec7ec6 100644 --- a/AUTHORS +++ b/AUTHORS
@@ -170,6 +170,7 @@ Gao Chun <chun.gao@intel.com> Gao Chun <gaochun.dev@gmail.com> George Liaskos <geo.liaskos@gmail.com> +Georgy Buranov <gburanov@gmail.com> Giuseppe Iuculano <giuseppe@iuculano.it> Glenn Adams <glenn@chromium.org> Gnanasekar Somanathan <gnanasekar.s@samsung.com> @@ -221,6 +222,7 @@ Jared Shumway <jaredshumway94@gmail.com> Jared Sohn <jared.sohn@gmail.com> Jared Wein <weinjared@gmail.com> +Jari Karppanen <jkarp@amazon.com> Jay Soffian <jaysoffian@gmail.com> Jeado Ko <haibane84@gmail.com> Jeongeun Kim <je_julie.kim@samsung.com> @@ -393,6 +395,7 @@ Pierre-Antoine LaFayette <pierre.lafayette@gmail.com> Po-Chun Chang <pochang0403@gmail.com> Pramod Begur Srinath <pramod.bs@samsung.com> +Pranay Kumar <pranay.kumar@samsung.com> Prashant Hiremath <prashhir@cisco.com> Prashant Nevase <prashant.n@samsung.com> Praveen Akkiraju <praveen.anp@samsung.com>
diff --git a/BUILD.gn b/BUILD.gn index a5d7cfd..fc5ecd4d 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -8,8 +8,10 @@ # you add a new build file, there must be some path of dependencies from this # file to your new one or GN won't know about it. +import("//build/config/crypto.gni") import("//build/config/features.gni") import("//build/config/ui.gni") +import("//build/module_args/v8.gni") import("//remoting/remoting_host.gni") if (is_android) { @@ -48,7 +50,6 @@ "//chrome/test/chromedriver:chromedriver_unittests", "//components:components_browsertests", "//components:components_unittests", - "//components/policy:policy_templates", "//content/shell:content_shell", "//content/test:content_browsertests", "//content/test:content_perftests", @@ -118,6 +119,7 @@ "//tools/imagediff($host_toolchain)", "//tools/gn", "//tools/gn:gn_unittests", + "//tools/gn:generate_test_gn_data", "//tools/telemetry:bitmaptools($host_toolchain)", "//ui/accessibility:accessibility_unittests", "//ui/app_list:app_list_unittests", @@ -131,11 +133,22 @@ deps += root_extra_deps - # TODO(GYP): Get this working on the mac? if (enable_extensions && !is_mac) { + # TODO(GYP): Get this working on the mac? deps += [ "//extensions/shell:app_shell_unittests" ] } + if (enable_me2me_host) { + deps += [ "//remoting/host:remoting_me2me_host" ] + } + + if (enable_media_router) { + deps += [ + "//chrome/browser/media/router/", + "//chrome/browser/media/router:unit_tests", + ] + } + if (enable_remoting_host) { deps += [ "//remoting:remoting_unittests", @@ -146,18 +159,6 @@ ] } - if (enable_me2me_host) { - deps += [ "//remoting/host:remoting_me2me_host" ] - } - - if (!is_win) { - deps += [ "//breakpad:symupload" ] - } - - if (use_x11) { - deps += [ "//tools/xdisplaycheck" ] - } - if (toolkit_views) { deps += [ "//ui/views:views_unittests" ] } @@ -170,17 +171,16 @@ deps += [ "//ui/ozone" ] } - if (enable_media_router) { - deps += [ - "//chrome/browser/media/router/", - "//chrome/browser/media/router:unit_tests", - ] + if (use_x11) { + deps += [ "//tools/xdisplaycheck" ] } - if (is_win || is_mac || is_chromeos) { - # RLZ works on these platforms. - # TODO(GYP): Is this target needed, or pulled in automatically? - deps += [ "//rlz:rlz_lib" ] + if (enable_configuration_policy) { + deps += [ "//components/policy:policy_templates" ] + } + + if (v8_use_external_startup_data) { + deps += [ "//gin:gin_v8_snapshot_fingerprint" ] } if (is_android) { @@ -221,7 +221,6 @@ "//ui/message_center:test_support", ] deps -= [ - "//breakpad:symupload", # TODO(GYP) ?? "//chrome", # TODO(GYP) ?? "//chrome/test:browser_tests", # TODO(GYP) ?? "//chrome/test:interactive_ui_tests", # TODO(GYP) ?? @@ -270,6 +269,7 @@ "//ppapi/examples/video_encode", "//third_party/pdfium/samples:pdfium_test", "//tools/gn", + "//tools/gn:generate_test_gn_data", "//tools/gn:gn_unittests", "//ui/app_list:app_list_unittests", "//url:url_unittests", @@ -280,6 +280,21 @@ } } + if (is_linux) { # TODO(GYP): || is_android || is_bsd? + deps += [ + "//breakpad:core-2-minidump", + "//breakpad:minidump-2-core", + ] + } + + if (is_chromeos || is_mac || is_win) { + deps += [ + "//rlz:rlz_id", + "//rlz:rlz_lib", + "//rlz:rlz_unittests", + ] + } + if (is_linux) { # The following are definitely linux-only. deps += [ @@ -302,33 +317,24 @@ } } - if (is_linux && !is_chromeos) { + if (is_win || (is_linux && !is_chromeos)) { + # TODO(GYP): Figure out which of these should (and can) build + # for android/chromeos/mac/ios. deps += [ - # TODO(GYP): Figure out which of these should (and can) build - # under which other conditions. "//base:base_perftests", "//base:base_i18n_perftests", "//base:check_example", "//base:protect_file_posix", "//base:build_utf8_validator_tables", - "//breakpad:core-2-minidump", - "//breakpad:minidump-2-core", - "//build/sanitizers:copy_llvm_symbolizer", - "//cc/blink:cc_blink_unittests", "//cc:cc_perftests", - "//chrome/test:chrome_app_unittests", + "//cc/blink:cc_blink_unittests", "//chrome/test:load_library_perf_tests", "//chrome/test:performance_browser_tests", "//chrome/test:sync_performance_tests", "//chrome/test/chromedriver:chromedriver", "//chrome/test/chromedriver:chromedriver_tests", "//chrome/tools/profile_reset:jtl_compiler", - "//cloud_print:cloud_print_unittests", "//components:components_perftests", - "//components/network_hints/browser", - "//components/webui_generator", - "//content/public/app:browser", - "//content/public/app:child", "//content/test:content_gl_tests", "//content/test:content_gl_benchmark", "//courgette:courgette", @@ -337,92 +343,48 @@ "//courgette:courgette_unittests", "//device:device_unittests", "//gin:gin_shell", - "//gin:gin_v8_snapshot_fingerprint", "//gin:gin_unittests", "//google_apis:google_apis_unittests", "//google_apis/gcm:mcs_probe", "//gpu:angle_unittests", - "//gpu:gl_tests", - - # TODO(GYP): Remove this when the gles2 tests work - "//gpu/command_buffer/client:gles2_implementation_no_check", - "//gpu:gpu_perftests", - "//gpu/khronos_glcts_support:khronos_glcts_test", # TODO(GYP) crbug.com/471903 to make this complete. + "//gpu:gl_tests", "//ipc:ipc_perftests", "//media:ffmpeg_regression_tests", # TODO(GYP) this should be conditional on media_use_ffmpeg "//media:media_perftests", - "//media/cast:cast_benchmarks", "//media/cast:generate_barcode_video", "//media/cast:generate_timecode_audio", - "//media/cast:tap_proxy", - "//mojo/application", "//net:crash_cache", "//net:crl_set_dump", "//net:dns_fuzz_stub", + "//net:dump_cache", "//net:gdig", "//net:get_server_time", "//net:net_watcher", # TODO(GYP): This should be conditional on use_v8_in_net + "//net:run_testserver", "//net:stress_cache", "//net:tld_cleanup", - "//net:run_testserver", - "//net:dump_cache", "//ppapi:pepper_hash_for_uma", - "//ppapi:ppapi_perftests", # TODO(GYP): Are there other ppapi_* test targets? - "//skia:filter_fuzz_stub", - "//skia:image_operations_bench", + "//ppapi:ppapi_perftests", "//sync:run_sync_testserver", "//sync:sync_endtoend_tests", - "//sync/tools:sync_client", - "//sync/tools:sync_listen_notifications", - "//testing/gmock:gmock_main", "//third_party/codesighs:maptsvdifftool", - "//third_party/libphonenumber:libphonenumber_unittests", - "//third_party/mojo/src/mojo/edk/test:mojo_public_system_perftests", - "//tools/gn:generate_test_gn_data", - "//tools/perf/clear_system_cache", - "//ui/keyboard:keyboard_unittests", - "//ui/message_center:message_center_unittests", - "//ui/snapshot:snapshot_unittests", - "//ui/views/examples:views_examples_with_content_exe", - - # "//v8:v8_snapshot", # TODO(GYP): visibility? - # "//v8:postmortem-metadata", # TODO(GYP): visibility? - - "//third_party/codesighs:nm2tsv", "//third_party/leveldatabase:env_chromium_unittests", "//third_party/libaddressinput:libaddressinput_unittests", - "//third_party/sqlite:sqlite_shell", + "//third_party/libphonenumber:libphonenumber_unittests", "//ui/compositor:compositor_unittests", ] - if (current_toolchain == host_toolchain) { - # Do not build the breakpad utilities in cross-compiles. - deps += [ - "//breakpad:dump_syms", - "//breakpad:microdump_stackwalk", - "//breakpad:minidump_dump", - "//breakpad:minidump_stackwalk", - ] - } - if (enable_extensions) { deps += [ "//extensions/shell:app_shell" ] } if (enable_nacl) { - deps += [ - "//components/nacl:nacl_loader_unittests", - "//remoting:remoting_key_tester", - ] + deps += [ "//components/nacl:nacl_loader_unittests" ] } - if (!is_debug && !is_component_build) { - deps += [ "//chrome/tools/service_discovery_sniffer" ] - } - - if (toolkit_views) { - deps += [ "//ui/app_list:app_list_demo" ] + if (enable_nacl && enable_remoting) { + deps += [ "//remoting:remoting_key_tester" ] } if (use_ash) { @@ -440,6 +402,63 @@ "//ui/aura:demo", ] } + } + + if (is_linux && !is_chromeos) { + deps += [ + # TODO(GYP): Figure out which of these should (and can) build + # under which other conditions. + "//build/sanitizers:copy_llvm_symbolizer", + "//chrome/test:chrome_app_unittests", + "//cloud_print:cloud_print_unittests", + "//components/network_hints/browser", + "//components/webui_generator", + "//content/public/app:browser", + "//content/public/app:child", + + # TODO(GYP): Remove this when the gles2 tests work + "//gpu/command_buffer/client:gles2_implementation_no_check", + + "//gpu/khronos_glcts_support:khronos_glcts_test", # TODO(GYP) crbug.com/471903 to make this complete. + "//media/cast:cast_benchmarks", + "//media/cast:tap_proxy", + "//mojo/application", + "//skia:filter_fuzz_stub", + "//skia:image_operations_bench", + "//sync/tools:sync_client", + "//sync/tools:sync_listen_notifications", + "//testing/gmock:gmock_main", + "//third_party/mojo/src/mojo/edk/test:mojo_public_system_perftests", + "//tools/perf/clear_system_cache", + "//ui/keyboard:keyboard_unittests", + "//ui/message_center:message_center_unittests", + "//ui/snapshot:snapshot_unittests", + "//ui/views/examples:views_examples_with_content_exe", + + # "//v8:v8_snapshot", # TODO(GYP): visibility? + # "//v8:postmortem-metadata", # TODO(GYP): visibility? + + "//third_party/codesighs:nm2tsv", + "//third_party/sqlite:sqlite_shell", + ] + + if (current_toolchain == host_toolchain) { + # Do not build the breakpad utilities in cross-compiles. + deps += [ + "//breakpad:dump_syms", + "//breakpad:microdump_stackwalk", + "//breakpad:minidump_dump", + "//breakpad:minidump_stackwalk", + ] + } + + if (!is_debug && !is_component_build) { + deps += [ "//chrome/tools/service_discovery_sniffer" ] + } + + if (toolkit_views) { + deps += [ "//ui/app_list:app_list_demo" ] + } if (use_x11) { deps += [ "//media:player_x11" ] @@ -453,7 +472,6 @@ deps += [ "//breakpad:crash_inspector", "//breakpad:dump_syms", - "//breakpad:symupload", "//third_party/apple_sample_code", "//third_party/molokocacao", ] @@ -506,12 +524,37 @@ "//ui/app_list:app_list_unittests", # TODO(GYP) "//ui/gfx:gfx_unittests", # TODO(GYP) ] - } else if (is_win) { - deps += [ "//ui/metro_viewer" ] + } + + if (is_win) { + deps += [ + "//base:pe_image_test", + "//chrome_elf:chrome_elf_unittests", + "//chrome_elf:dll_hash_main", + + # "//components/crash/tools:crash_service", TODO(GYP) - doesn't fully build yet. + "//components/wifi:wifi_test", + "//net:quic_client", + "//net:quic_server", + "//sandbox/win:pocdll", + "//sandbox/win:sandbox_poc", + "//sandbox/win:sbox_integration_tests", + "//sandbox/win:sbox_unittests", + "//sandbox/win:sbox_validation_tests", + "//testing/gtest:gtest_main", + "//third_party/codesighs:msmap2tsv", + "//third_party/pdfium/samples:pdfium_diff", + "//ui/metro_viewer", + ] deps -= [ "//crypto:crypto_unittests", # TODO(GYP) "//net:net_unittests", # TODO(GYP) ] + } else { + if (!is_android) { + # TODO(GYP): Make this work on android also. + deps += [ "//breakpad:symupload" ] + } } }
diff --git a/DEPS b/DEPS index da52a20..6e7977d 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': '846a3f3643c4bdbbf5b85978852f61c608094376', # from svn revision 193629 + 'webkit_revision': 'bb7e4b1448d1fa2d1b55dcbb130aefb8f7f070f1', # from svn revision 193681 'chromium_git': 'https://chromium.googlesource.com', 'chromiumos_git': 'https://chromium.googlesource.com/chromiumos', 'pdfium_git': 'https://pdfium.googlesource.com', @@ -42,12 +42,12 @@ 'boringssl_git': 'https://boringssl.googlesource.com', 'libvpx_revision': '1fff3e3550a605f7edf72280ed8fcaa83eeb586e', 'sfntly_revision': '1bdaae8fc788a5ac8936d68bf24f37d977a13dac', - 'skia_revision': '64b309c35bfddb8382c3e38f1d8ff7efe4098cab', + 'skia_revision': '7ef63c85c5891ca59906e3c783a7f954be3f7f62', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and V8 without interference from each other. 'v8_branch': 'trunk', - 'v8_revision': '065a2495d4d592d0c2af93a49543d8ea210332d2', + 'v8_revision': '441e976ecca14a1603bee4211cc821d468367291', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling WebRTC # and V8 without interference from each other. @@ -66,7 +66,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '1ed2ceb70476b135a3dedbb45549d6b3bc6ecdea', + 'pdfium_revision': 'eddab4425614e49146f904f00da4a664ba4b581b', # 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. @@ -78,7 +78,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling nss # and whatever else without interference from each other. - 'nss_revision': 'd1edb68688b91a380fb2025b3420fad68db54ed6', # from svn revision 294684 + 'nss_revision': '95068068df410e398ac221a9195c999b22bd63e9', # from svn revision 294785 # Three lines of non-changing comments so that # the commit queue can handle CLs rolling google-toolbox-for-mac # and whatever else without interference from each other. @@ -210,7 +210,7 @@ Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '104f872faf2cd809cdada885a1e39be85e5b3316', 'src/third_party/libjingle/source/talk': - Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + '61d33e57aae9faa4c8bf8e788c66df0f749a9465', + Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + 'd872289cd2805dba53009a17543221ce50220ea1', 'src/third_party/usrsctp/usrsctplib': Var('chromium_git') + '/external/usrsctplib.git' + '@' + '36444a999739e9e408f8f587cb4c3ffeef2e50ac', # from svn revision 9215 @@ -234,7 +234,7 @@ Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067', 'src/third_party/webrtc': - Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'cc8ca89e85299fd62fdaf6d494c8963e17d188dc', + Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '5ffd4ec78c21a89fd4926d561315e3c699a5021a', 'src/third_party/openmax_dl': Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' + Var('openmax_dl_revision'), @@ -243,7 +243,7 @@ Var('chromium_git') + '/external/github.com/open-source-parsers/jsoncpp.git' + '@' + 'f572e8e42e22cfcf5ab0aea26574f408943edfa4', # from svn 248 'src/third_party/libyuv': - Var('chromium_git') + '/external/libyuv.git' + '@' + 'd204db647e591ccf0e2589236ecea90330d65a66', # from svn revision 1171 + Var('chromium_git') + '/external/libyuv.git' + '@' + '32ad6e0e12fec058efdf85a5a4b32ed657f27c36', # from svn revision 1368 'src/third_party/smhasher/src': Var('chromium_git') + '/external/smhasher.git' + '@' + 'e87738e57558e0ec472b2fc3a643b838e5b6e88f',
diff --git a/android_webview/browser/aw_browser_main_parts.cc b/android_webview/browser/aw_browser_main_parts.cc index db47f02..d894e7e 100644 --- a/android_webview/browser/aw_browser_main_parts.cc +++ b/android_webview/browser/aw_browser_main_parts.cc
@@ -60,8 +60,6 @@ ui::ResourceBundle::DO_NOT_LOAD_COMMON_RESOURCES); std::string locale = l10n_util::GetApplicationLocale(std::string()) + ".pak"; if (AwAssets::OpenAsset(locale, &pak_fd, &pak_off, &pak_len)) { - VLOG(0) << "Load from apk succesful, fd=" << pak_fd << " off=" << pak_off - << " len=" << pak_len; ui::ResourceBundle::CleanupSharedInstance(); ui::ResourceBundle::InitSharedInstanceWithPakFileRegion( base::File(pak_fd), base::MemoryMappedFile::Region(pak_off, pak_len)); @@ -73,8 +71,6 @@ // Try to directly mmap the webviewchromium.pak from the apk. Fall back to // load from file, using PATH_SERVICE, otherwise. if (AwAssets::OpenAsset("webviewchromium.pak", &pak_fd, &pak_off, &pak_len)) { - VLOG(0) << "Loading webviewchromium.pak from, fd:" << pak_fd - << " off:" << pak_off << " len:" << pak_len; ui::ResourceBundle::GetSharedInstance().AddDataPackFromFileRegion( base::File(pak_fd), base::MemoryMappedFile::Region(pak_off, pak_len),
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentViewClient.java b/android_webview/java/src/org/chromium/android_webview/AwContentViewClient.java index 2246be3..168ea65 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContentViewClient.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContentViewClient.java
@@ -5,6 +5,7 @@ package org.chromium.android_webview; import android.annotation.SuppressLint; +import android.app.SearchManager; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; @@ -189,4 +190,23 @@ public boolean isExternalFlingActive() { return mAwContents.isFlingActive(); } + + @Override + public boolean doesPerformWebSearch() { + return true; + } + + @Override + public void performWebSearch(String query) { + Intent i = new Intent(Intent.ACTION_WEB_SEARCH); + i.putExtra(SearchManager.EXTRA_NEW_SEARCH, true); + i.putExtra(SearchManager.QUERY, query); + i.putExtra(Browser.EXTRA_APPLICATION_ID, mContext.getPackageName()); + i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + mContext.startActivity(i); + } catch (android.content.ActivityNotFoundException ex) { + // If no app handles it, do nothing. + } + } }
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 3079e33..4e8baa3 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -234,8 +234,8 @@ private boolean mHasRequestedVisitedHistoryFromClient; // TODO(boliu): This should be in a global context, not per webview. private final double mDIPScale; - // Whether the WebView has attempted to do any load (including uncommitted loads). - private boolean mDidAttemptLoad = false; + // Whether this WebView is a popup. + private boolean mIsPopupWindow = false; // The base background color, i.e. not accounting for any CSS body from the current page. private int mBaseBackgroundColor = Color.WHITE; @@ -961,8 +961,7 @@ if (wasWindowFocused) onWindowFocusChanged(wasWindowFocused); if (wasFocused) onFocusChanged(true, 0, null); - // Popups are always assumed as having made a load attempt. - mDidAttemptLoad = true; + mIsPopupWindow = true; // Restore injected JavaScript interfaces. for (Map.Entry<String, Pair<Object, Class>> entry : javascriptInterfaces.entrySet()) { @@ -2301,10 +2300,8 @@ nativeInsertVisualStateCallback(mNativeAwContents, requestId, callback); } - public boolean getDidAttemptLoad() { - if (mDidAttemptLoad) return mDidAttemptLoad; - mDidAttemptLoad = mWebContentsObserver.hasStartedNonApiProvisionalLoadInMainFrame(); - return mDidAttemptLoad; + public boolean isPopupWindow() { + return mIsPopupWindow; } //--------------------------------------------------------------------------------------------
diff --git a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java index 509a6de..675f5b1 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java +++ b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java
@@ -219,8 +219,8 @@ @Override public void navigationStateChanged(int flags) { if ((flags & InvalidateTypes.URL) != 0 - && mAwContents.hasAccessedInitialDocument() - && mAwContents.getDidAttemptLoad()) { + && mAwContents.isPopupWindow() + && mAwContents.hasAccessedInitialDocument()) { // Hint the client to show the last committed url, as it may be unsafe to show // the pending entry. String url = mAwContents.getLastCommittedUrl();
diff --git a/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java b/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java index 2652e851..de5dfb13 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java +++ b/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java
@@ -6,11 +6,9 @@ import org.chromium.android_webview.AwContents.VisualStateCallback; import org.chromium.base.ThreadUtils; -import org.chromium.content_public.browser.NavigationEntry; import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContentsObserver; import org.chromium.net.NetError; -import org.chromium.ui.base.PageTransition; import java.lang.ref.WeakReference; @@ -24,7 +22,6 @@ // and should be found and cleaned up. private final WeakReference<AwContents> mAwContents; private final WeakReference<AwContentsClient> mAwContentsClient; - private boolean mStartedNonApiProvisionalLoadInMainFrame = false; public AwWebContentsObserver( WebContents webContents, AwContents awContents, AwContentsClient awContentsClient) { @@ -33,10 +30,6 @@ mAwContentsClient = new WeakReference<>(awContentsClient); } - boolean hasStartedNonApiProvisionalLoadInMainFrame() { - return mStartedNonApiProvisionalLoadInMainFrame; - } - @Override public void didFinishLoad(long frameId, String validatedUrl, boolean isMainFrame) { AwContentsClient client = mAwContentsClient.get(); @@ -103,23 +96,4 @@ if (client == null) return; client.doUpdateVisitedHistory(url, isReload); } - - @Override - public void didStartProvisionalLoadForFrame( - long frameId, - long parentFrameId, - boolean isMainFrame, - String validatedUrl, - boolean isErrorPage, - boolean isIframeSrcdoc) { - if (!isMainFrame) return; - AwContents awContents = mAwContents.get(); - if (awContents != null) { - NavigationEntry pendingEntry = awContents.getNavigationController().getPendingEntry(); - if (pendingEntry != null - && (pendingEntry.getTransition() & PageTransition.FROM_API) == 0) { - mStartedNonApiProvisionalLoadInMainFrame = true; - } - } - } }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java index a431f1a..3ec8c45 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java
@@ -275,6 +275,18 @@ TimeUnit.MILLISECONDS); } + /** + * Stops loading on the UI thread. + */ + public void stopLoading(final AwContents awContents) { + getInstrumentation().runOnMainSync(new Runnable() { + @Override + public void run() { + awContents.stopLoading(); + } + }); + } + public void waitForVisualStateCallback(final AwContents awContents) throws Exception { final CallbackHelper ch = new CallbackHelper(); final int chCount = ch.getCallCount();
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnPageFinishedTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnPageFinishedTest.java index a574fc0..6336c1cd 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnPageFinishedTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnPageFinishedTest.java
@@ -15,6 +15,8 @@ import org.chromium.content.browser.test.util.TestCallbackHelperContainer; import org.chromium.net.test.util.TestWebServer; +import java.util.concurrent.CountDownLatch; + /** * Tests for the ContentViewClient.onPageFinished() method. */ @@ -39,7 +41,7 @@ @MediumTest @Feature({"AndroidWebView"}) - public void testOnPageFinishedPassesCorrectUrl() throws Throwable { + public void testPassesCorrectUrl() throws Throwable { TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = mContentsClient.getOnPageFinishedHelper(); @@ -53,7 +55,7 @@ @MediumTest @Feature({"AndroidWebView"}) - public void testOnPageFinishedCalledAfterError() throws Throwable { + public void testCalledAfterError() throws Throwable { class LocalTestClient extends TestAwContentsClient { private boolean mIsOnReceivedErrorCalled = false; private boolean mIsOnPageFinishedCalled = false; @@ -110,7 +112,7 @@ @MediumTest @Feature({"AndroidWebView"}) - public void testOnPageFinishedCalledAfterRedirectedUrlIsOverridden() throws Throwable { + public void testCalledAfterRedirectedUrlIsOverridden() throws Throwable { /* * If url1 is redirected url2, and url2 load is overridden, onPageFinished should still be * called for url2. @@ -149,7 +151,7 @@ @MediumTest @Feature({"AndroidWebView"}) - public void testOnPageFinishedNotCalledForValidSubresources() throws Throwable { + public void testNotCalledForValidSubresources() throws Throwable { TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = mContentsClient.getOnPageFinishedHelper(); @@ -188,7 +190,7 @@ @MediumTest @Feature({"AndroidWebView"}) - public void testOnPageFinishedNotCalledForHistoryApi() throws Throwable { + public void testNotCalledForHistoryApi() throws Throwable { TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = mContentsClient.getOnPageFinishedHelper(); enableJavaScriptOnUiThread(mAwContents); @@ -227,13 +229,13 @@ @MediumTest @Feature({"AndroidWebView"}) - public void testOnPageFinishedCalledForHrefNavigations() throws Throwable { + public void testCalledForHrefNavigations() throws Throwable { doTestOnPageFinishedCalledForHrefNavigations(false); } @MediumTest @Feature({"AndroidWebView"}) - public void testOnPageFinishedCalledForHrefNavigationsWithBaseUrl() throws Throwable { + public void testCalledForHrefNavigationsWithBaseUrl() throws Throwable { doTestOnPageFinishedCalledForHrefNavigations(true); } @@ -282,7 +284,7 @@ @MediumTest @Feature({"AndroidWebView"}) - public void testOnPageFinishedNotCalledOnDomModificationForBlankWebView() throws Throwable { + public void testNotCalledOnDomModificationForBlankWebView() throws Throwable { TestWebServer webServer = TestWebServer.start(); try { doTestOnPageFinishedNotCalledOnDomMutation(webServer, null); @@ -293,7 +295,7 @@ @MediumTest @Feature({"AndroidWebView"}) - public void testOnPageFinishedNotCalledOnDomModificationAfterNonCommittedLoadFromApi() + public void testNotCalledOnDomModificationAfterNonCommittedLoadFromApi() throws Throwable { enableJavaScriptOnUiThread(mAwContents); TestWebServer webServer = TestWebServer.start(); @@ -308,7 +310,57 @@ @MediumTest @Feature({"AndroidWebView"}) - public void testOnPageFinishedNotCalledOnDomModificationAfterLoadUrl() throws Throwable { + public void testNotCalledOnDomModificationWithJavascriptUrlAfterNonCommittedLoadFromApi() + throws Throwable { + enableJavaScriptOnUiThread(mAwContents); + TestWebServer webServer = TestWebServer.start(); + try { + final CountDownLatch latch = new CountDownLatch(1); + final String url = webServer.setResponseWithRunnableAction( + "/about.html", CommonResources.ABOUT_HTML, null, + new Runnable() { + @Override + public void run() { + try { + latch.await(WAIT_TIMEOUT_MS, + java.util.concurrent.TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + fail("Caught InterruptedException " + e); + } + } + }); + TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = + mContentsClient.getOnPageFinishedHelper(); + final int onPageFinishedCallCount = onPageFinishedHelper.getCallCount(); + loadUrlAsync(mAwContents, url); + loadUrlAsync(mAwContents, + "javascript:(function(){document.body.innerHTML='Hello,%20World!';})()"); + stopLoading(mAwContents); + // We now have 3 possible outcomes: + // - the good one -- onPageFinished only fires for the first load; + // - two bad ones: + // - onPageFinished fires for the dom mutation, then for the first load. (1) + // - onPageFinished fires for the first load, then for the dom mutation; (2) + // We verify that (1) doesn't happen with the code below. Then we load a sync page, + // and make sure that we are getting onPageFinished for the sync page, not due + // to the dom mutation, thus verifying that (2) doesn't happen as well. + onPageFinishedHelper.waitForCallback(onPageFinishedCallCount); + assertEquals(url, onPageFinishedHelper.getUrl()); + assertEquals(onPageFinishedCallCount + 1, onPageFinishedHelper.getCallCount()); + latch.countDown(); // Release the server. + final String syncUrl = webServer.setResponse("/sync.html", "", null); + loadUrlAsync(mAwContents, syncUrl); + onPageFinishedHelper.waitForCallback(onPageFinishedCallCount + 1); + assertEquals(syncUrl, onPageFinishedHelper.getUrl()); + assertEquals(onPageFinishedCallCount + 2, onPageFinishedHelper.getCallCount()); + } finally { + webServer.shutdown(); + } + } + + @MediumTest + @Feature({"AndroidWebView"}) + public void testNotCalledOnDomModificationAfterLoadUrl() throws Throwable { TestWebServer webServer = TestWebServer.start(); try { final String testUrl = @@ -322,7 +374,7 @@ @MediumTest @Feature({"AndroidWebView"}) - public void testOnPageFinishedNotCalledOnDomModificationAfterLoadData() + public void testNotCalledOnDomModificationAfterLoadData() throws Throwable { TestWebServer webServer = TestWebServer.start(); try { @@ -358,7 +410,7 @@ @MediumTest @Feature({"AndroidWebView"}) - public void testOnPageFinishedCalledAfter204Reply() throws Throwable { + public void testCalledAfter204Reply() throws Throwable { TestWebServer webServer = TestWebServer.start(); try { final String url = webServer.setResponseWithNoContentStatus("/page.html");
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnReceivedError2Test.java b/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnReceivedError2Test.java index c5ab9dae..6007de0 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnReceivedError2Test.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnReceivedError2Test.java
@@ -359,7 +359,7 @@ mContentsClient.getOnPageFinishedHelper(); final int onPageFinishedCallCount = onPageFinishedHelper.getCallCount(); loadUrlAsync(mAwContents, url); - mAwContents.stopLoading(); + stopLoading(mAwContents); onPageFinishedHelper.waitForCallback(onPageFinishedCallCount, 1 /* numberOfCallsToWaitFor */, WAIT_TIMEOUT_MS,
diff --git a/base/BUILD.gn b/base/BUILD.gn index 137f61c..b9f134e3 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -894,7 +894,7 @@ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] } -if (is_linux && !is_chromeos) { +if (is_win || (is_linux && !is_chromeos)) { # TODO(GYP): Figure out which of these work and are needed on other platforms. test("base_perftests") { sources = [ @@ -1250,6 +1250,7 @@ "test/histogram_tester_unittest.cc", "test/test_reg_util_win_unittest.cc", "test/trace_event_analyzer_unittest.cc", + "test/user_action_tester_unittest.cc", "threading/non_thread_safe_unittest.cc", "threading/platform_thread_unittest.cc", "threading/sequenced_worker_pool_unittest.cc", @@ -1374,7 +1375,6 @@ set_sources_assignment_filter([]) sources += [ "debug/proc_maps_linux_unittest.cc" ] set_sources_assignment_filter(sources_assignment_filter) - sources -= [ "files/file_path_watcher_unittest.cc" ] } # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
diff --git a/base/android/build_info.h b/base/android/build_info.h index e4e84e8..9d73bdb 100644 --- a/base/android/build_info.h +++ b/base/android/build_info.h
@@ -18,8 +18,6 @@ // This enumeration maps to the values returned by BuildInfo::sdk_int(), // indicating the Android release associated with a given SDK version. enum SdkVersion { - SDK_VERSION_ICE_CREAM_SANDWICH = 14, - SDK_VERSION_ICE_CREAM_SANDWICH_MR1 = 15, SDK_VERSION_JELLY_BEAN = 16, SDK_VERSION_JELLY_BEAN_MR1 = 17, SDK_VERSION_JELLY_BEAN_MR2 = 18,
diff --git a/base/android/java/src/org/chromium/base/AccessedByNative.java b/base/android/java/src/org/chromium/base/annotations/AccessedByNative.java similarity index 93% rename from base/android/java/src/org/chromium/base/AccessedByNative.java rename to base/android/java/src/org/chromium/base/annotations/AccessedByNative.java index 3e163fc..6df7c110 100644 --- a/base/android/java/src/org/chromium/base/AccessedByNative.java +++ b/base/android/java/src/org/chromium/base/annotations/AccessedByNative.java
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.base; +package org.chromium.base.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention;
diff --git a/base/android/java/src/org/chromium/base/CalledByNativeUnchecked.java b/base/android/java/src/org/chromium/base/annotations/CalledByNativeUnchecked.java similarity index 96% rename from base/android/java/src/org/chromium/base/CalledByNativeUnchecked.java rename to base/android/java/src/org/chromium/base/annotations/CalledByNativeUnchecked.java index d5e9b74..c0abcbe6 100644 --- a/base/android/java/src/org/chromium/base/CalledByNativeUnchecked.java +++ b/base/android/java/src/org/chromium/base/annotations/CalledByNativeUnchecked.java
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.base; +package org.chromium.base.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention;
diff --git a/base/android/java/src/org/chromium/base/UsedByReflection.java b/base/android/java/src/org/chromium/base/annotations/UsedByReflection.java similarity index 95% rename from base/android/java/src/org/chromium/base/UsedByReflection.java rename to base/android/java/src/org/chromium/base/annotations/UsedByReflection.java index 7d18fb0..a2af704 100644 --- a/base/android/java/src/org/chromium/base/UsedByReflection.java +++ b/base/android/java/src/org/chromium/base/annotations/UsedByReflection.java
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.base; +package org.chromium.base.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Target;
diff --git a/base/android/java/src/org/chromium/base/library_loader/Linker.java b/base/android/java/src/org/chromium/base/library_loader/Linker.java index dbeb758..7e509987 100644 --- a/base/android/java/src/org/chromium/base/library_loader/Linker.java +++ b/base/android/java/src/org/chromium/base/library_loader/Linker.java
@@ -10,10 +10,10 @@ import android.os.Parcelable; import android.util.Log; -import org.chromium.base.AccessedByNative; import org.chromium.base.CalledByNative; import org.chromium.base.SysUtils; import org.chromium.base.ThreadUtils; +import org.chromium.base.annotations.AccessedByNative; import java.io.FileNotFoundException; import java.util.HashMap;
diff --git a/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java b/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java index 732fe6e..89bee99 100644 --- a/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java +++ b/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java
@@ -6,11 +6,11 @@ import android.graphics.Rect; -import org.chromium.base.AccessedByNative; import org.chromium.base.CalledByNative; -import org.chromium.base.CalledByNativeUnchecked; import org.chromium.base.JNINamespace; import org.chromium.base.NativeClassQualifiedName; +import org.chromium.base.annotations.AccessedByNative; +import org.chromium.base.annotations.CalledByNativeUnchecked; import java.util.ArrayList; import java.util.Iterator;
diff --git a/base/base.gyp b/base/base.gyp index 50a57ea..b9362b4 100644 --- a/base/base.gyp +++ b/base/base.gyp
@@ -632,6 +632,7 @@ 'test/test_pending_task_unittest.cc', 'test/test_reg_util_win_unittest.cc', 'test/trace_event_analyzer_unittest.cc', + 'test/user_action_tester_unittest.cc', 'threading/non_thread_safe_unittest.cc', 'threading/platform_thread_unittest.cc', 'threading/sequenced_worker_pool_unittest.cc', @@ -828,7 +829,6 @@ ['OS == "android"', { 'sources/': [ ['include', '^debug/proc_maps_linux_unittest\\.cc$'], - ['exclude', '^files/file_path_watcher_unittest\\.cc$'], ], }], # Enable more direct string conversions on platforms with native utf8 @@ -1011,6 +1011,8 @@ 'test/trace_event_analyzer.h', 'test/trace_to_file.cc', 'test/trace_to_file.h', + 'test/user_action_tester.cc', + 'test/user_action_tester.h', 'test/values_test_util.cc', 'test/values_test_util.h', ],
diff --git a/base/files/file_path_watcher.cc b/base/files/file_path_watcher.cc index b173541..59ae7059 100644 --- a/base/files/file_path_watcher.cc +++ b/base/files/file_path_watcher.cc
@@ -32,7 +32,7 @@ // FSEvents isn't available on iOS and is broken on OSX 10.6 and earlier. // See http://crbug.com/54822#c31 return mac::IsOSLionOrLater(); -#elif defined(OS_WIN) || defined(OS_LINUX) +#elif defined(OS_WIN) || defined(OS_LINUX) || defined(OS_ANDROID) return true; #else return false;
diff --git a/base/files/file_path_watcher_unittest.cc b/base/files/file_path_watcher_unittest.cc index bc7e6307..0e1c4672 100644 --- a/base/files/file_path_watcher_unittest.cc +++ b/base/files/file_path_watcher_unittest.cc
@@ -31,6 +31,10 @@ #include "base/threading/thread.h" #include "testing/gtest/include/gtest/gtest.h" +#if defined(OS_ANDROID) +#include "base/android/path_utils.h" +#endif // defined(OS_ANDROID) + namespace base { namespace { @@ -150,7 +154,17 @@ // Create a separate file thread in order to test proper thread usage. base::Thread::Options options(MessageLoop::TYPE_IO, 0); ASSERT_TRUE(file_thread_.StartWithOptions(options)); +#if defined(OS_ANDROID) + // Watching files is only permitted when all parent directories are + // accessible, which is not the case for the default temp directory + // on Android which is under /data/data. Use /sdcard instead. + // TODO(pauljensen): Remove this when crbug.com/475568 is fixed. + FilePath parent_dir; + ASSERT_TRUE(android::GetExternalStorageDirectory(&parent_dir)); + ASSERT_TRUE(temp_dir_.CreateUniqueTempDirUnderPath(parent_dir)); +#else // defined(OS_ANDROID) ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); +#endif // defined(OS_ANDROID) collector_ = new NotificationCollector(); } @@ -526,9 +540,16 @@ ASSERT_TRUE(WriteFile(child_dir_file1, "content")); ASSERT_TRUE(WaitForEvents()); +// Apps cannot change file attributes on Android in /sdcard as /sdcard uses the +// "fuse" file system, while /data uses "ext4". Running these tests in /data +// would be preferable and allow testing file attributes and symlinks. +// TODO(pauljensen): Re-enable when crbug.com/475568 is fixed and SetUp() places +// the |temp_dir_| in /data. +#if !defined(OS_ANDROID) // Modify "$dir/subdir/subdir_child_dir/child_dir_file1" attributes. ASSERT_TRUE(base::MakeFileUnreadable(child_dir_file1)); ASSERT_TRUE(WaitForEvents()); +#endif // Delete "$dir/subdir/subdir_file1". ASSERT_TRUE(base::DeleteFile(subdir_file1, false)); @@ -541,6 +562,14 @@ } #if defined(OS_POSIX) +#if defined(OS_ANDROID) +// Apps cannot create symlinks on Android in /sdcard as /sdcard uses the +// "fuse" file system, while /data uses "ext4". Running these tests in /data +// would be preferable and allow testing file attributes and symlinks. +// TODO(pauljensen): Re-enable when crbug.com/475568 is fixed and SetUp() places +// the |temp_dir_| in /data. +#define RecursiveWithSymLink DISABLED_RecursiveWithSymLink +#endif // defined(OS_ANDROID) TEST_F(FilePathWatcherTest, RecursiveWithSymLink) { if (!FilePathWatcher::RecursiveWatchAvailable()) return; @@ -610,6 +639,14 @@ } // Verify that changing attributes on a file is caught +#if defined(OS_ANDROID) +// Apps cannot change file attributes on Android in /sdcard as /sdcard uses the +// "fuse" file system, while /data uses "ext4". Running these tests in /data +// would be preferable and allow testing file attributes and symlinks. +// TODO(pauljensen): Re-enable when crbug.com/475568 is fixed and SetUp() places +// the |temp_dir_| in /data. +#define FileAttributesChanged DISABLED_FileAttributesChanged +#endif // defined(OS_ANDROID TEST_F(FilePathWatcherTest, FileAttributesChanged) { ASSERT_TRUE(WriteFile(test_file(), "content")); FilePathWatcher watcher;
diff --git a/base/md5.cc b/base/md5.cc index 064e28ac..eff5308 100644 --- a/base/md5.cc +++ b/base/md5.cc
@@ -277,7 +277,7 @@ ret.resize(32); for (int i = 0, j = 0; i < 16; i++, j += 2) { - int a = digest.a[i]; + uint8_t a = digest.a[i]; ret[j] = zEncode[(a >> 4) & 0xf]; ret[j + 1] = zEncode[a & 0xf]; }
diff --git a/base/memory/ref_counted.h b/base/memory/ref_counted.h index 219437e..5f94b4c 100644 --- a/base/memory/ref_counted.h +++ b/base/memory/ref_counted.h
@@ -14,6 +14,7 @@ #ifndef NDEBUG #include "base/logging.h" #endif +#include "base/move.h" #include "base/threading/thread_collision_warner.h" #include "build/build_config.h" @@ -264,6 +265,7 @@ // template <class T> class scoped_refptr { + TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_refptr) public: typedef T element_type; @@ -286,6 +288,11 @@ AddRef(ptr_); } + template <typename U> + scoped_refptr(scoped_refptr<U>&& r) : ptr_(r.get()) { + r.ptr_ = nullptr; + } + ~scoped_refptr() { if (ptr_) Release(ptr_); @@ -323,6 +330,17 @@ return *this = r.get(); } + scoped_refptr<T>& operator=(scoped_refptr<T>&& r) { + scoped_refptr<T>(r.Pass()).swap(*this); + return *this; + } + + template <typename U> + scoped_refptr<T>& operator=(scoped_refptr<U>&& r) { + scoped_refptr<T>(r.Pass()).swap(*this); + return *this; + } + void swap(T** pp) { T* p = ptr_; ptr_ = *pp; @@ -334,6 +352,8 @@ } private: + template <typename U> friend class scoped_refptr; + // Allow scoped_refptr<T> to be used in boolean expressions, but not // implicitly convertible to a real bool (which is dangerous). //
diff --git a/base/memory/ref_counted_unittest.cc b/base/memory/ref_counted_unittest.cc index f75cd38..6f8e599 100644 --- a/base/memory/ref_counted_unittest.cc +++ b/base/memory/ref_counted_unittest.cc
@@ -40,19 +40,71 @@ static bool was_destroyed() { return was_destroyed_; } - void SelfDestruct() { self_ptr_ = NULL; } + static void reset_was_destroyed() { was_destroyed_ = false; } + + scoped_refptr<ScopedRefPtrToSelf> self_ptr_; private: friend class base::RefCounted<ScopedRefPtrToSelf>; ~ScopedRefPtrToSelf() { was_destroyed_ = true; } static bool was_destroyed_; - - scoped_refptr<ScopedRefPtrToSelf> self_ptr_; }; bool ScopedRefPtrToSelf::was_destroyed_ = false; +class ScopedRefPtrCountBase : public base::RefCounted<ScopedRefPtrCountBase> { + public: + ScopedRefPtrCountBase() { ++constructor_count_; } + + static int constructor_count() { return constructor_count_; } + + static int destructor_count() { return destructor_count_; } + + static void reset_count() { + constructor_count_ = 0; + destructor_count_ = 0; + } + + protected: + virtual ~ScopedRefPtrCountBase() { ++destructor_count_; } + + private: + friend class base::RefCounted<ScopedRefPtrCountBase>; + + static int constructor_count_; + static int destructor_count_; +}; + +int ScopedRefPtrCountBase::constructor_count_ = 0; +int ScopedRefPtrCountBase::destructor_count_ = 0; + +class ScopedRefPtrCountDerived : public ScopedRefPtrCountBase { + public: + ScopedRefPtrCountDerived() { ++constructor_count_; } + + static int constructor_count() { return constructor_count_; } + + static int destructor_count() { return destructor_count_; } + + static void reset_count() { + constructor_count_ = 0; + destructor_count_ = 0; + } + + protected: + ~ScopedRefPtrCountDerived() override { ++destructor_count_; } + + private: + friend class base::RefCounted<ScopedRefPtrCountDerived>; + + static int constructor_count_; + static int destructor_count_; +}; + +int ScopedRefPtrCountDerived::constructor_count_ = 0; +int ScopedRefPtrCountDerived::destructor_count_ = 0; + } // end namespace TEST(RefCountedUnitTest, TestSelfAssignment) { @@ -66,10 +118,24 @@ CheckDerivedMemberAccess check; } -TEST(RefCountedUnitTest, ScopedRefPtrToSelf) { +TEST(RefCountedUnitTest, ScopedRefPtrToSelfPointerAssignment) { + ScopedRefPtrToSelf::reset_was_destroyed(); + ScopedRefPtrToSelf* check = new ScopedRefPtrToSelf(); EXPECT_FALSE(ScopedRefPtrToSelf::was_destroyed()); - check->SelfDestruct(); + check->self_ptr_ = nullptr; + EXPECT_TRUE(ScopedRefPtrToSelf::was_destroyed()); +} + +TEST(RefCountedUnitTest, ScopedRefPtrToSelfMoveAssignment) { + ScopedRefPtrToSelf::reset_was_destroyed(); + + ScopedRefPtrToSelf* check = new ScopedRefPtrToSelf(); + EXPECT_FALSE(ScopedRefPtrToSelf::was_destroyed()); + // Releasing |check->self_ptr_| will delete |check|. + // The move assignment operator must assign |check->self_ptr_| first then + // release |check->self_ptr_|. + check->self_ptr_ = scoped_refptr<ScopedRefPtrToSelf>(); EXPECT_TRUE(ScopedRefPtrToSelf::was_destroyed()); } @@ -113,3 +179,284 @@ EXPECT_EQ(p1, p2); EXPECT_EQ(p2, p1); } + +TEST(RefCountedUnitTest, SelfMoveAssignment) { + ScopedRefPtrCountBase::reset_count(); + + { + ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase(); + scoped_refptr<ScopedRefPtrCountBase> p(raw); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + p = p.Pass(); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(raw, p.get()); + + // p goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); +} + +TEST(RefCountedUnitTest, MoveAssignment1) { + ScopedRefPtrCountBase::reset_count(); + + { + ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase(); + scoped_refptr<ScopedRefPtrCountBase> p1(raw); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + { + scoped_refptr<ScopedRefPtrCountBase> p2; + + p2 = p1.Pass(); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(nullptr, p1.get()); + EXPECT_EQ(raw, p2.get()); + + // p2 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); + + // p1 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); +} + +TEST(RefCountedUnitTest, MoveAssignment2) { + ScopedRefPtrCountBase::reset_count(); + + { + ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase(); + scoped_refptr<ScopedRefPtrCountBase> p1; + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + { + scoped_refptr<ScopedRefPtrCountBase> p2(raw); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + p1 = p2.Pass(); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(raw, p1.get()); + EXPECT_EQ(nullptr, p2.get()); + + // p2 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + // p1 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); +} + +TEST(RefCountedUnitTest, MoveAssignmentSameInstance1) { + ScopedRefPtrCountBase::reset_count(); + + { + ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase(); + scoped_refptr<ScopedRefPtrCountBase> p1(raw); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + { + scoped_refptr<ScopedRefPtrCountBase> p2(p1); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + p1 = p2.Pass(); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(raw, p1.get()); + EXPECT_EQ(nullptr, p2.get()); + + // p2 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + // p1 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); +} + +TEST(RefCountedUnitTest, MoveAssignmentSameInstance2) { + ScopedRefPtrCountBase::reset_count(); + + { + ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase(); + scoped_refptr<ScopedRefPtrCountBase> p1(raw); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + { + scoped_refptr<ScopedRefPtrCountBase> p2(p1); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + p2 = p1.Pass(); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(nullptr, p1.get()); + EXPECT_EQ(raw, p2.get()); + + // p2 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); + + // p1 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); +} + +TEST(RefCountedUnitTest, MoveAssignmentDifferentInstances) { + ScopedRefPtrCountBase::reset_count(); + + { + ScopedRefPtrCountBase *raw1 = new ScopedRefPtrCountBase(); + scoped_refptr<ScopedRefPtrCountBase> p1(raw1); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + { + ScopedRefPtrCountBase *raw2 = new ScopedRefPtrCountBase(); + scoped_refptr<ScopedRefPtrCountBase> p2(raw2); + EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + p1 = p2.Pass(); + EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(raw2, p1.get()); + EXPECT_EQ(nullptr, p2.get()); + + // p2 goes out of scope. + } + EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); + + // p1 goes out of scope. + } + EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(2, ScopedRefPtrCountBase::destructor_count()); +} + +TEST(RefCountedUnitTest, MoveAssignmentDerived) { + ScopedRefPtrCountBase::reset_count(); + ScopedRefPtrCountDerived::reset_count(); + + { + ScopedRefPtrCountBase *raw1 = new ScopedRefPtrCountBase(); + scoped_refptr<ScopedRefPtrCountBase> p1(raw1); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountDerived::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count()); + + { + ScopedRefPtrCountDerived *raw2 = new ScopedRefPtrCountDerived(); + scoped_refptr<ScopedRefPtrCountDerived> p2(raw2); + EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count()); + + p1 = p2.Pass(); + EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count()); + EXPECT_EQ(raw2, p1.get()); + EXPECT_EQ(nullptr, p2.get()); + + // p2 goes out of scope. + } + EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count()); + + // p1 goes out of scope. + } + EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(2, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count()); +} + +TEST(RefCountedUnitTest, MoveConstructor) { + ScopedRefPtrCountBase::reset_count(); + + { + ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase(); + scoped_refptr<ScopedRefPtrCountBase> p1(raw); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + { + scoped_refptr<ScopedRefPtrCountBase> p2(p1.Pass()); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(nullptr, p1.get()); + EXPECT_EQ(raw, p2.get()); + + // p2 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); + + // p1 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); +} + +TEST(RefCountedUnitTest, MoveConstructorDerived) { + ScopedRefPtrCountBase::reset_count(); + ScopedRefPtrCountDerived::reset_count(); + + { + ScopedRefPtrCountDerived *raw1 = new ScopedRefPtrCountDerived(); + scoped_refptr<ScopedRefPtrCountDerived> p1(raw1); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count()); + + { + scoped_refptr<ScopedRefPtrCountBase> p2(p1.Pass()); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count()); + EXPECT_EQ(nullptr, p1.get()); + EXPECT_EQ(raw1, p2.get()); + + // p2 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count()); + + // p1 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count()); +} +
diff --git a/base/move.h b/base/move.h index 06f3f323..91fd0e7 100644 --- a/base/move.h +++ b/base/move.h
@@ -226,4 +226,9 @@ typedef void MoveOnlyTypeForCPP03; \ private: +#define TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(type) \ + public: \ + type&& Pass() WARN_UNUSED_RESULT { return static_cast<type&&>(*this); } \ + private: + #endif // BASE_MOVE_H_
diff --git a/base/synchronization/cancellation_flag.cc b/base/synchronization/cancellation_flag.cc index ad3b551..ca5c0a8 100644 --- a/base/synchronization/cancellation_flag.cc +++ b/base/synchronization/cancellation_flag.cc
@@ -19,4 +19,8 @@ return base::subtle::Acquire_Load(&flag_) != 0; } +void CancellationFlag::UnsafeResetForTesting() { + base::subtle::Release_Store(&flag_, 0); +} + } // namespace base
diff --git a/base/synchronization/cancellation_flag.h b/base/synchronization/cancellation_flag.h index 51a4def1..0f0f08ee 100644 --- a/base/synchronization/cancellation_flag.h +++ b/base/synchronization/cancellation_flag.h
@@ -29,6 +29,11 @@ void Set(); bool IsSet() const; // Returns true iff the flag was set. + // For subtle reasons that may be different on different architectures, + // a different thread testing IsSet() may erroneously read 'true' after + // this method has been called. + void UnsafeResetForTesting(); + private: base::subtle::Atomic32 flag_; #if !defined(NDEBUG)
diff --git a/base/test/BUILD.gn b/base/test/BUILD.gn index 6872aff9..8baeb147 100644 --- a/base/test/BUILD.gn +++ b/base/test/BUILD.gn
@@ -116,6 +116,8 @@ "trace_event_analyzer.h", "trace_to_file.cc", "trace_to_file.h", + "user_action_tester.cc", + "user_action_tester.h", "values_test_util.cc", "values_test_util.h", ]
diff --git a/base/test/launcher/test_launcher.cc b/base/test/launcher/test_launcher.cc index 0b09004d..ac79d756d 100644 --- a/base/test/launcher/test_launcher.cc +++ b/base/test/launcher/test_launcher.cc
@@ -150,7 +150,7 @@ KillSpawnedTestProcesses(); // The signal would normally kill the process, so exit now. - exit(1); + _exit(1); } void OnFileCanWriteWithoutBlocking(int fd) override { NOTREACHED(); }
diff --git a/base/test/user_action_tester.cc b/base/test/user_action_tester.cc new file mode 100644 index 0000000..3fdab12 --- /dev/null +++ b/base/test/user_action_tester.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 "base/test/user_action_tester.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" + +namespace base { + +UserActionTester::UserActionTester() + : action_callback_( + base::Bind(&UserActionTester::OnUserAction, base::Unretained(this))) { + base::AddActionCallback(action_callback_); +} + +UserActionTester::~UserActionTester() { + base::RemoveActionCallback(action_callback_); +} + +int UserActionTester::GetActionCount(const std::string& user_action) const { + UserActionCountMap::const_iterator iter = count_map_.find(user_action); + return iter == count_map_.end() ? 0 : iter->second; +} + +void UserActionTester::ResetCounts() { + count_map_.clear(); +} + +void UserActionTester::OnUserAction(const std::string& user_action) { + ++(count_map_[user_action]); +} + +} // namespace base
diff --git a/base/test/user_action_tester.h b/base/test/user_action_tester.h new file mode 100644 index 0000000..6b0efc5 --- /dev/null +++ b/base/test/user_action_tester.h
@@ -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. + +#ifndef BASE_TEST_USER_ACTION_TESTER_H_ +#define BASE_TEST_USER_ACTION_TESTER_H_ + +#include <map> +#include <string> + +#include "base/metrics/user_metrics.h" + +namespace base { + +// This class observes and collects user action notifications that are sent +// by the tests, so that they can be examined afterwards for correctness. +// Note: This class is NOT thread-safe. +class UserActionTester { + public: + UserActionTester(); + ~UserActionTester(); + + // Returns the number of times the given |user_action| occurred. + int GetActionCount(const std::string& user_action) const; + + // Resets all user action counts to 0. + void ResetCounts(); + + private: + typedef std::map<std::string, int> UserActionCountMap; + + // The callback that is notified when a user actions occurs. + void OnUserAction(const std::string& user_action); + + // A map that tracks the number of times a user action has occurred. + UserActionCountMap count_map_; + + // The callback that is added to the global action callback list. + base::ActionCallback action_callback_; + + DISALLOW_COPY_AND_ASSIGN(UserActionTester); +}; + +} // namespace base + +#endif // BASE_TEST_USER_ACTION_TESTER_H_
diff --git a/base/test/user_action_tester_unittest.cc b/base/test/user_action_tester_unittest.cc new file mode 100644 index 0000000..a51849f6 --- /dev/null +++ b/base/test/user_action_tester_unittest.cc
@@ -0,0 +1,86 @@ +// 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/test/user_action_tester.h" + +#include "base/metrics/user_metrics.h" +#include "base/metrics/user_metrics_action.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace base { + +namespace { + +const char kUserAction1[] = "user.action.1"; +const char kUserAction2[] = "user.action.2"; +const char kUserAction3[] = "user.action.3"; + +// Record an action and cause all ActionCallback observers to be notified. +void RecordAction(const char user_action[]) { + base::RecordAction(base::UserMetricsAction(user_action)); +} + +} // namespace + +// Verify user action counts are zero initially. +TEST(UserActionTesterTest, GetActionCountWhenNoActionsHaveBeenRecorded) { + UserActionTester user_action_tester; + EXPECT_EQ(0, user_action_tester.GetActionCount(kUserAction1)); +} + +// Verify user action counts are tracked properly. +TEST(UserActionTesterTest, GetActionCountWhenActionsHaveBeenRecorded) { + UserActionTester user_action_tester; + + RecordAction(kUserAction1); + RecordAction(kUserAction2); + RecordAction(kUserAction2); + + EXPECT_EQ(1, user_action_tester.GetActionCount(kUserAction1)); + EXPECT_EQ(2, user_action_tester.GetActionCount(kUserAction2)); + EXPECT_EQ(0, user_action_tester.GetActionCount(kUserAction3)); +} + +// Verify no seg faults occur when resetting action counts when none have been +// recorded. +TEST(UserActionTesterTest, ResetCountsWhenNoActionsHaveBeenRecorded) { + UserActionTester user_action_tester; + user_action_tester.ResetCounts(); +} + +// Verify user action counts are set to zero on a ResetCounts. +TEST(UserActionTesterTest, ResetCountsWhenActionsHaveBeenRecorded) { + UserActionTester user_action_tester; + + RecordAction(kUserAction1); + RecordAction(kUserAction1); + RecordAction(kUserAction2); + user_action_tester.ResetCounts(); + + EXPECT_EQ(0, user_action_tester.GetActionCount(kUserAction1)); + EXPECT_EQ(0, user_action_tester.GetActionCount(kUserAction2)); + EXPECT_EQ(0, user_action_tester.GetActionCount(kUserAction3)); +} + +// Verify the UserActionsTester is notified when base::RecordAction is called. +TEST(UserActionTesterTest, VerifyUserActionTesterListensForUserActions) { + UserActionTester user_action_tester; + + base::RecordAction(base::UserMetricsAction(kUserAction1)); + + EXPECT_EQ(1, user_action_tester.GetActionCount(kUserAction1)); +} + +// Verify the UserActionsTester is notified when base::RecordComputedAction is +// called. +TEST(UserActionTesterTest, + VerifyUserActionTesterListensForComputedUserActions) { + UserActionTester user_action_tester; + + base::RecordComputedAction(kUserAction1); + + EXPECT_EQ(1, user_action_tester.GetActionCount(kUserAction1)); +} + +} // namespace base
diff --git a/build/android/pylib/base/base_test_runner.py b/build/android/pylib/base/base_test_runner.py index 4e2eae70..1ca03383 100644 --- a/build/android/pylib/base/base_test_runner.py +++ b/build/android/pylib/base/base_test_runner.py
@@ -26,12 +26,11 @@ class BaseTestRunner(object): """Base class for running tests on a single device.""" - def __init__(self, device_serial, tool, cleanup_test_files=False): + def __init__(self, device_serial, tool): """ Args: device: Tests will run on the device of this ID. tool: Name of the Valgrind tool. - cleanup_test_files: Whether or not to cleanup test files on device. """ self.device_serial = device_serial self.device = device_utils.DeviceUtils(device_serial) @@ -45,7 +44,6 @@ # starting it in TestServerThread. self.test_server_spawner_port = 0 self.test_server_port = 0 - self._cleanup_test_files = cleanup_test_files def _PushTestServerPortInfoToDevice(self): """Pushes the latest port information to device.""" @@ -77,8 +75,6 @@ def TearDown(self): """Run once after all tests are run.""" self.ShutdownHelperToolsForTestSuite() - if self._cleanup_test_files: - self.device.old_interface.RemovePushedFiles() def LaunchTestHttpServer(self, document_root, port=None, extra_config_contents=None):
diff --git a/build/android/pylib/device/device_utils.py b/build/android/pylib/device/device_utils.py index f7167ce..3ad767b 100644 --- a/build/android/pylib/device/device_utils.py +++ b/build/android/pylib/device/device_utils.py
@@ -27,6 +27,7 @@ from pylib import constants from pylib.device import adb_wrapper from pylib.device import decorators +from pylib.device import device_blacklist from pylib.device import device_errors from pylib.device import intent from pylib.device import logcat_monitor @@ -72,6 +73,7 @@ }, ] + @decorators.WithExplicitTimeoutAndRetries( _DEFAULT_TIMEOUT, _DEFAULT_RETRIES) def GetAVDs(): @@ -1505,7 +1507,7 @@ """Creates a Parallelizer to operate over the provided list of devices. If |devices| is either |None| or an empty list, the Parallelizer will - operate over all attached devices. + operate over all attached devices that have not been blacklisted. Args: devices: A list of either DeviceUtils instances or objects from @@ -1518,9 +1520,12 @@ A Parallelizer operating over |devices|. """ if not devices: - devices = adb_wrapper.AdbWrapper.GetDevices() + blacklist = device_blacklist.ReadBlacklist() + devices = [d for d in adb_wrapper.AdbWrapper.GetDevices() + if d.GetDeviceSerial() not in blacklist] if not devices: raise device_errors.NoDevicesError() + devices = [d if isinstance(d, cls) else cls(d) for d in devices] if async: return parallelizer.Parallelizer(devices)
diff --git a/build/android/pylib/gtest/test_options.py b/build/android/pylib/gtest/test_options.py index 5099ba6..58cd82b 100644 --- a/build/android/pylib/gtest/test_options.py +++ b/build/android/pylib/gtest/test_options.py
@@ -8,7 +8,6 @@ GTestOptions = collections.namedtuple('GTestOptions', [ 'tool', - 'cleanup_test_files', 'gtest_filter', 'run_disabled', 'test_arguments',
diff --git a/build/android/pylib/gtest/test_package_exe.py b/build/android/pylib/gtest/test_package_exe.py index e607cad..ee95b5c 100644 --- a/build/android/pylib/gtest/test_package_exe.py +++ b/build/android/pylib/gtest/test_package_exe.py
@@ -6,6 +6,7 @@ import logging import os +import posixpath import sys import tempfile @@ -119,14 +120,19 @@ #override def GetAllTests(self, device): - cmd = '%s %s/%s --gtest_list_tests' % (self.tool.GetTestWrapper(), - constants.TEST_EXECUTABLE_DIR, self.suite_name) - lib_path = '%s/%s_deps' % (constants.TEST_EXECUTABLE_DIR, self.suite_name) - (exit_code, output) = device.old_interface.GetAndroidToolStatusAndOutput( - cmd, lib_path=lib_path) - if exit_code != 0: - raise Exception( - 'Failed to start binary:\n%s' % '\n'.join(output)) + lib_path = posixpath.join( + constants.TEST_EXECUTABLE_DIR, '%s_deps' % self.suite_name) + + cmd = [] + for wrapper in (device.GetDevicePieWrapper(), self.tool.GetTestWrapper()): + if wrapper: + cmd.append(wrapper) + cmd.extend([ + posixpath.join(constants.TEST_EXECUTABLE_DIR, self.suite_name), + '--gtest_list_tests']) + + output = device.RunShellCommand( + cmd, check_return=True, env={'LD_LIBRARY_PATH': lib_path}) return gtest_test_instance.ParseGTestListTests(output) #override
diff --git a/build/android/pylib/gtest/test_runner.py b/build/android/pylib/gtest/test_runner.py index 4bb9737..0fc6c12 100644 --- a/build/android/pylib/gtest/test_runner.py +++ b/build/android/pylib/gtest/test_runner.py
@@ -49,8 +49,7 @@ test_package: An instance of TestPackage class. """ - super(TestRunner, self).__init__(device, test_options.tool, - test_options.cleanup_test_files) + super(TestRunner, self).__init__(device, test_options.tool) self.test_package = test_package self.test_package.tool = self.tool
diff --git a/build/android/pylib/host_driven/setup.py b/build/android/pylib/host_driven/setup.py index 285bcd40..b2ed348 100644 --- a/build/android/pylib/host_driven/setup.py +++ b/build/android/pylib/host_driven/setup.py
@@ -195,7 +195,6 @@ def TestRunnerFactory(device, shard_index): return test_runner.HostDrivenTestRunner( device, shard_index, - instrumentation_options.tool, - instrumentation_options.cleanup_test_files) + instrumentation_options.tool) return (TestRunnerFactory, available_tests)
diff --git a/build/android/pylib/host_driven/test_case.py b/build/android/pylib/host_driven/test_case.py index 8c372cda..a7c6a18 100644 --- a/build/android/pylib/host_driven/test_case.py +++ b/build/android/pylib/host_driven/test_case.py
@@ -50,8 +50,6 @@ instrumentation_options: An InstrumentationOptions object. """ class_name = self.__class__.__name__ - self.adb = None - self.cleanup_test_files = False self.device = None self.device_id = '' self.has_forwarded_ports = False @@ -67,15 +65,12 @@ # TODO(bulach): make ports_to_forward not optional and move the Forwarder # mapping here. - def SetUp(self, device, shard_index, - cleanup_test_files, ports_to_forward=None): + def SetUp(self, device, shard_index, ports_to_forward=None): if not ports_to_forward: ports_to_forward = [] self.device_id = device self.shard_index = shard_index self.device = device_utils.DeviceUtils(self.device_id) - self.adb = self.device.old_interface - self.cleanup_test_files = cleanup_test_files if ports_to_forward: self.ports_to_forward = ports_to_forward
diff --git a/build/android/pylib/host_driven/test_runner.py b/build/android/pylib/host_driven/test_runner.py index 865be20..5e175bc 100644 --- a/build/android/pylib/host_driven/test_runner.py +++ b/build/android/pylib/host_driven/test_runner.py
@@ -47,23 +47,27 @@ result, rather than being re-raised on the main thread. """ + # TODO(jbudorick): Remove cleanup_test_files once it's no longer used. + # pylint: disable=unused-argument #override - def __init__(self, device, shard_index, tool, cleanup_test_files): + def __init__(self, device, shard_index, tool, cleanup_test_files=None): """Creates a new HostDrivenTestRunner. Args: device: Attached android device. shard_index: Shard index. tool: Name of the Valgrind tool. - cleanup_test_files: Whether or not to cleanup test files on device. + cleanup_test_files: Deprecated. """ - super(HostDrivenTestRunner, self).__init__(device, tool, cleanup_test_files) + super(HostDrivenTestRunner, self).__init__(device, tool) # The shard index affords the ability to create unique port numbers (e.g. # DEFAULT_PORT + shard_index) if the test so wishes. self.shard_index = shard_index + # pylint: enable=unused-argument + #override def RunTest(self, test): """Sets up and runs a test case. @@ -82,7 +86,7 @@ exception_raised = False try: - test.SetUp(str(self.device), self.shard_index, self._cleanup_test_files) + test.SetUp(str(self.device), self.shard_index) except Exception: logging.exception( 'Caught exception while trying to run SetUp() for test: ' +
diff --git a/build/android/pylib/instrumentation/test_options.py b/build/android/pylib/instrumentation/test_options.py index 4a16b11..792010b8 100644 --- a/build/android/pylib/instrumentation/test_options.py +++ b/build/android/pylib/instrumentation/test_options.py
@@ -8,7 +8,6 @@ InstrumentationOptions = collections.namedtuple('InstrumentationOptions', [ 'tool', - 'cleanup_test_files', 'annotations', 'exclude_annotations', 'test_filter',
diff --git a/build/android/pylib/instrumentation/test_runner.py b/build/android/pylib/instrumentation/test_runner.py index f3983fd9..adc424b0 100644 --- a/build/android/pylib/instrumentation/test_runner.py +++ b/build/android/pylib/instrumentation/test_runner.py
@@ -48,8 +48,7 @@ test_pkg: A TestPackage object. additional_flags: A list of additional flags to add to the command line. """ - super(TestRunner, self).__init__(device, test_options.tool, - test_options.cleanup_test_files) + super(TestRunner, self).__init__(device, test_options.tool) self._lighttp_port = constants.LIGHTTPD_RANDOM_PORT_FIRST + shard_index self._logcat_monitor = None
diff --git a/build/android/pylib/linker/setup.py b/build/android/pylib/linker/setup.py index ff21f10..5776f5af 100644 --- a/build/android/pylib/linker/setup.py +++ b/build/android/pylib/linker/setup.py
@@ -40,7 +40,6 @@ if t.qualified_name in filtered_test_names] def TestRunnerFactory(device, _shard_index): - return test_runner.LinkerTestRunner( - device, args.tool, args.cleanup_test_files) + return test_runner.LinkerTestRunner(device, args.tool) return (TestRunnerFactory, all_tests)
diff --git a/build/android/pylib/linker/test_runner.py b/build/android/pylib/linker/test_runner.py index 3680f83..b6803e4 100644 --- a/build/android/pylib/linker/test_runner.py +++ b/build/android/pylib/linker/test_runner.py
@@ -49,16 +49,14 @@ """ #override - def __init__(self, device, tool, cleanup_test_files): + def __init__(self, device, tool): """Creates a new LinkerTestRunner. Args: device: Attached android device. tool: Name of the Valgrind tool. - cleanup_test_files: Whether or not to cleanup test files on device. """ - - super(LinkerTestRunner, self).__init__(device, tool, cleanup_test_files) + super(LinkerTestRunner, self).__init__(device, tool) #override def InstallTestPackage(self): @@ -68,8 +66,7 @@ if not os.path.exists(apk_path): raise Exception('%s not found, please build it' % apk_path) - package_name = apk_helper.GetPackageName(apk_path) - self.device.old_interface.ManagedInstall(apk_path, package_name) + self.device.Install(apk_path) #override def RunTest(self, test):
diff --git a/build/android/pylib/perf/perf_control.py b/build/android/pylib/perf/perf_control.py index 97fa4a7..b6a0989e 100644 --- a/build/android/pylib/perf/perf_control.py +++ b/build/android/pylib/perf/perf_control.py
@@ -28,7 +28,7 @@ def SetHighPerfMode(self): """Sets the highest stable performance mode for the device.""" - if not self._device.old_interface.IsRootEnabled(): + if not self._device.HasRoot(): message = 'Need root for performance mode. Results may be NOISY!!' logging.warning(message) # Add an additional warning at exit, such that it's clear that any results @@ -58,13 +58,13 @@ self._ForceAllCpusOnline(True) self._SetScalingGovernorInternal('performance') if not self._AllCpusAreOnline(): - if not self._device.old_interface.IsRootEnabled(): + if not self._device.HasRoot(): raise RuntimeError('Need root to force CPUs online.') raise RuntimeError('Failed to force CPUs online.') def SetDefaultPerfMode(self): """Sets the performance mode for the device to its default mode.""" - if not self._device.old_interface.IsRootEnabled(): + if not self._device.HasRoot(): return product_model = self._device.product_model if 'Nexus 5' == product_model:
diff --git a/build/android/pylib/perf/test_runner.py b/build/android/pylib/perf/test_runner.py index da66d07..9d1f437 100644 --- a/build/android/pylib/perf/test_runner.py +++ b/build/android/pylib/perf/test_runner.py
@@ -170,7 +170,7 @@ tests: a dict mapping test_name to command. flaky_tests: a list of flaky test_name. """ - super(TestRunner, self).__init__(device, None, 'Release') + super(TestRunner, self).__init__(device, None) self._options = test_options self._shard_index = shard_index self._max_shard = max_shard
diff --git a/build/android/pylib/screenshot.py b/build/android/pylib/screenshot.py index ea939b7..2bbde037 100644 --- a/build/android/pylib/screenshot.py +++ b/build/android/pylib/screenshot.py
@@ -6,6 +6,7 @@ import os import signal import tempfile +import time from pylib import cmd_helper from pylib.device import device_errors @@ -87,10 +88,13 @@ Returns: Output video file name on the host. """ - host_file_name = host_file or ('screen-recording-%s.mp4' % - self._device.old_interface.GetTimestamp()) + # TODO(jbudorick): Merge filename generation with the logic for doing so in + # DeviceUtils. + host_file_name = ( + host_file + or 'screen-recording-%s.mp4' % time.strftime('%Y%m%dT%H%M%S', + time.localtime())) host_file_name = os.path.abspath(host_file_name) - self._device.old_interface.EnsureHostDirectory(host_file_name) self._device.PullFile(self._device_file, host_file_name) self._device.RunShellCommand('rm -f "%s"' % self._device_file) return host_file_name
diff --git a/build/android/pylib/uiautomator/test_options.py b/build/android/pylib/uiautomator/test_options.py index b383b201..3f5f950 100644 --- a/build/android/pylib/uiautomator/test_options.py +++ b/build/android/pylib/uiautomator/test_options.py
@@ -8,7 +8,6 @@ UIAutomatorOptions = collections.namedtuple('UIAutomatorOptions', [ 'tool', - 'cleanup_test_files', 'annotations', 'exclude_annotations', 'test_filter',
diff --git a/build/android/pylib/uiautomator/test_runner.py b/build/android/pylib/uiautomator/test_runner.py index d7a4bdf..296bd47 100644 --- a/build/android/pylib/uiautomator/test_runner.py +++ b/build/android/pylib/uiautomator/test_runner.py
@@ -26,7 +26,6 @@ # Create an InstrumentationOptions object to pass to the super class instrumentation_options = instr_test_options.InstrumentationOptions( test_options.tool, - test_options.cleanup_test_files, test_options.annotations, test_options.exclude_annotations, test_options.test_filter,
diff --git a/build/android/pylib/utils/test_environment.py b/build/android/pylib/utils/test_environment.py index 4d88a45..e78eb5c 100644 --- a/build/android/pylib/utils/test_environment.py +++ b/build/android/pylib/utils/test_environment.py
@@ -34,13 +34,14 @@ """Clean up the test environment, restarting fresh adb and HTTP daemons.""" _KillWebServers() device_utils.RestartServer() - p = device_utils.DeviceUtils.parallel() - p.old_interface.RestartAdbdOnDevice() - try: - p.EnableRoot() - except device_errors.CommandFailedError as e: - # TODO(jbudorick) Handle this exception appropriately after interface - # conversions are finished. - logging.error(str(e)) - p.WaitUntilFullyBooted() + + def cleanup_device(d): + d.old_interface.RestartAdbdOnDevice() + try: + d.EnableRoot() + except device_errors.CommandFailedError as e: + logging.error(str(e)) + d.WaitUntilFullyBooted() + + device_utils.DeviceUtils.parallel().pMap(cleanup_device)
diff --git a/build/android/test_runner.py b/build/android/test_runner.py index b1bd6e7..23d46b71 100755 --- a/build/android/test_runner.py +++ b/build/android/test_runner.py
@@ -175,9 +175,6 @@ def AddDeviceOptions(parser): """Adds device options to |parser|.""" group = parser.add_argument_group(title='Device Options') - group.add_argument('-c', dest='cleanup_test_files', - help='Cleanup test files on the device after run', - action='store_true') group.add_argument('--tool', dest='tool', help=('Run the test under a tool ' @@ -372,7 +369,6 @@ # TODO(jbudorick): Get rid of InstrumentationOptions. return instrumentation_test_options.InstrumentationOptions( args.tool, - args.cleanup_test_files, args.annotations, args.exclude_annotations, args.test_filter, @@ -437,7 +433,6 @@ return uiautomator_test_options.UIAutomatorOptions( args.tool, - args.cleanup_test_files, args.annotations, args.exclude_annotations, args.test_filter, @@ -636,7 +631,6 @@ # into the gtest code. gtest_options = gtest_test_options.GTestOptions( args.tool, - args.cleanup_test_files, args.test_filter, args.run_disabled, args.test_arguments,
diff --git a/build/android/update_verification.py b/build/android/update_verification.py index fe89567..9539d94 100755 --- a/build/android/update_verification.py +++ b/build/android/update_verification.py
@@ -17,7 +17,7 @@ def _SaveAppData(device, package_name, from_apk=None, data_dir=None): def _BackupAppData(data_dir=None): - device.old_interface.Adb().SendCommand('backup %s' % package_name) + device.adb.Backup(package_name) backup_file = os.path.join(os.getcwd(), 'backup.ab') assert os.path.exists(backup_file), 'Backup failed.' if data_dir: @@ -29,8 +29,7 @@ if from_apk: logging.info('Installing %s...', from_apk) - # TODO(jbudorick) Switch to AdbWrapper.Install on the impl switch. - output = device.old_interface.Install(from_apk, reinstall=True) + output = device.Install(from_apk, reinstall=True) if 'Success' not in output: raise Exception('Unable to install %s. output: %s' % (from_apk, output)) @@ -42,14 +41,13 @@ def _VerifyAppUpdate(device, to_apk, app_data, from_apk=None): def _RestoreAppData(): assert os.path.exists(app_data), 'Backup file does not exist!' - device.old_interface.Adb().SendCommand('restore %s' % app_data) + device.adb.Restore(app_data) # It seems restore command is not synchronous. time.sleep(15) if from_apk: logging.info('Installing %s...', from_apk) - # TODO(jbudorick) Switch to AdbWrapper.Install on the impl switch. - output = device.old_interface.Install(from_apk, reinstall=True) + output = device.Install(from_apk, reinstall=True) if 'Success' not in output: raise Exception('Unable to install %s. output: %s' % (from_apk, output)) @@ -59,8 +57,7 @@ logging.info('Verifying that %s cannot be installed side-by-side...', to_apk) - # TODO(jbudorick) Switch to AdbWrapper.Install on the impl switch. - output = device.old_interface.Install(to_apk) + output = device.Install(to_apk) if 'INSTALL_FAILED_ALREADY_EXISTS' not in output: if 'Success' in output: raise Exception('Package name has changed! output: %s' % output) @@ -68,8 +65,7 @@ raise Exception(output) logging.info('Verifying that %s can be overinstalled...', to_apk) - # TODO(jbudorick) Switch to AdbWrapper.Install on the impl switch. - output = device.old_interface.Install(to_apk, reinstall=True) + output = device.adb.Install(to_apk, reinstall=True) if 'Success' not in output: raise Exception('Unable to install %s.\n output: %s' % (to_apk, output)) logging.info('Successfully updated to the new apk. Please verify that the '
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni index 22310d4..8185b03f 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni
@@ -733,7 +733,7 @@ # datadeps, testonly # # Example -# java_library("foo") { +# java_binary("foo") { # java_files = [ "org/chromium/foo/FooMain.java" ] # deps = [ ":bar_java" ] # main_class = "org.chromium.foo.FooMain" @@ -834,7 +834,7 @@ } } -# Declare an java library target +# Declare a java library target # # Variables # deps: Specifies the dependencies of this target. Java targets in this list @@ -932,7 +932,7 @@ } } -# Declare an java library target for a prebuilt jar +# Declare a java library target for a prebuilt jar # # Variables # deps: Specifies the dependencies of this target. Java targets in this list
diff --git a/build/gn_migration.gypi b/build/gn_migration.gypi index 0da18bdb..1f9f178 100644 --- a/build/gn_migration.gypi +++ b/build/gn_migration.gypi
@@ -254,6 +254,12 @@ '../remoting/remoting.gyp:remoting_key_tester', ], }], + ['toolkit_views==1', { + 'dependencies': [ + '../ui/app_list/app_list.gyp:app_list_demo', + '../ui/views/views.gyp:views_unittests', + ], + }], ['use_x11==1', { 'dependencies': [ '../media/media.gyp:player_x11', @@ -267,12 +273,6 @@ }], ], }], - ['toolkit_views==1', { - 'dependencies': [ - '../ui/app_list/app_list.gyp:app_list_demo', - '../ui/views/views.gyp:views_unittests', - ], - }], ['use_ash==1', { 'dependencies': [ '../ash/ash.gyp:ash_shell', @@ -295,7 +295,9 @@ }], ['OS=="win" or OS=="mac" or chromeos==1', { 'dependencies': [ + '../rlz/rlz.gyp:rlz_id', '../rlz/rlz.gyp:rlz_lib', + '../rlz/rlz.gyp:rlz_unittests', ], }], ['OS=="android"', { @@ -364,6 +366,11 @@ '../url/url.gyp:url_unittests', ], }], + ['OS=="android" or OS=="linux"', { + 'dependencies': [ + '../net/net.gyp:disk_cache_memory_test', + ], + }], ['OS=="linux"', { 'dependencies': [ '../breakpad/breakpad.gyp:breakpad_unittests', @@ -443,7 +450,21 @@ }], ['OS=="win"', { 'dependencies': [ + '../base/base.gyp:pe_image_test', + '../chrome_elf/chrome_elf.gyp:chrome_elf_unittests', + '../chrome_elf/chrome_elf.gyp:dll_hash_main', + '../components/components.gyp:wifi_test', + '../net/net.gyp:quic_client', + '../net/net.gyp:quic_server', + '../sandbox/sandbox.gyp:pocdll', + '../sandbox/sandbox.gyp:sandbox_poc', + '../sandbox/sandbox.gyp:sbox_integration_tests', + '../sandbox/sandbox.gyp:sbox_unittests', + '../sandbox/sandbox.gyp:sbox_validation_tests', + '../testing/gtest.gyp:gtest_main', '../third_party/codesighs/codesighs.gyp:msdump2symdb', + '../third_party/codesighs/codesighs.gyp:msmap2tsv', + '../third_party/pdfium/samples/samples.gyp:pdfium_diff', '../win8/win8.gyp:metro_viewer', ], }, { @@ -451,18 +472,13 @@ '../third_party/codesighs/codesighs.gyp:nm2tsv', ], }], - ['OS=="android" or OS=="linux"', { - 'dependencies': [ - '../net/net.gyp:disk_cache_memory_test', - ], - }], ], }, { 'target_name': 'gyp_only', 'type': 'none', 'conditions': [ - ['OS=="linux"', { + ['OS=="linux" or OS=="win"', { 'conditions': [ ['disable_nacl==0 and disable_nacl_untrusted==0', { 'dependencies': [ @@ -529,6 +545,7 @@ }], ['use_openssl==1', { 'dependencies': [ + # TODO(GYP): All of these targets still need to be converted. '../third_party/boringssl/boringssl_tests.gyp:boringssl_ecdsa_test', '../third_party/boringssl/boringssl_tests.gyp:boringssl_bn_test', '../third_party/boringssl/boringssl_tests.gyp:boringssl_pqueue_test', @@ -558,16 +575,17 @@ '../third_party/boringssl/boringssl_tests.gyp:boringssl_unittests', ], }], - ['OS=="linux"', { + ['OS=="linux" or OS=="win"', { 'dependencies': [ + # TODO(GYP): in progress - see tfarina. '../third_party/webrtc/tools/tools.gyp:frame_analyzer', '../third_party/webrtc/tools/tools.gyp:rgba_to_i420_converter', ], }], ['OS=="win"', { 'dependencies': [ + # TODO(GYP): All of these targets still need to be converted. '../base/base.gyp:debug_message', - '../base/base.gyp:pe_image_test', '../chrome/chrome.gyp:app_installer', '../chrome/chrome.gyp:app_installer_unittests', '../chrome/chrome.gyp:app_shim', @@ -581,11 +599,6 @@ '../chrome/chrome.gyp:setup_unittests', '../chrome/installer/mini_installer.gyp:mini_installer', '../chrome/tools/crash_service/caps/caps.gyp:caps', - '../chrome_elf/chrome_elf.gyp:blacklist_test_dll_2', - '../chrome_elf/chrome_elf.gyp:blacklist_test_dll_3', - '../chrome_elf/chrome_elf.gyp:blacklist_test_main_dll', - '../chrome_elf/chrome_elf.gyp:chrome_elf_unittests', - '../chrome_elf/chrome_elf.gyp:dll_hash_main', '../cloud_print/gcp20/prototype/gcp20_device.gyp:gcp20_device', '../cloud_print/gcp20/prototype/gcp20_device.gyp:gcp20_device_unittests', '../cloud_print/service/service.gyp:cloud_print_service', @@ -593,33 +606,18 @@ '../cloud_print/service/service.gyp:cloud_print_service_setup', '../cloud_print/virtual_driver/win/install/virtual_driver_install.gyp:virtual_driver_setup', '../cloud_print/virtual_driver/win/virtual_driver.gyp:gcp_portmon', - '../components/components.gyp:wifi_test', '../content/content_shell_and_tests.gyp:content_shell_crash_service', '../content/content_shell_and_tests.gyp:layout_test_helper', '../content/content_shell_and_tests.gyp:video_decode_accelerator_unittest', '../gpu/gpu.gyp:angle_end2end_tests', '../gpu/gpu.gyp:angle_perftests', '../net/net.gyp:net_docs', - '../net/net.gyp:quic_client', - '../net/net.gyp:quic_server', '../ppapi/ppapi_internal.gyp:ppapi_perftests', '../remoting/app_remoting_test.gyp:ar_sample_test_driver', '../remoting/remoting.gyp:remoting_breakpad_tester', '../remoting/remoting.gyp:remoting_console', '../remoting/remoting.gyp:remoting_desktop', '../rlz/rlz.gyp:rlz', - '../rlz/rlz.gyp:rlz_id', - '../rlz/rlz.gyp:rlz_unittests', - '../sandbox/sandbox.gyp:pocdll', - '../sandbox/sandbox.gyp:sandbox_poc', - '../sandbox/sandbox.gyp:sbox_integration_tests', - '../sandbox/sandbox.gyp:sbox_unittests', - '../sandbox/sandbox.gyp:sbox_validation_tests', - '../testing/gtest.gyp:gtest_main', - '../third_party/codesighs/codesighs.gyp:msmap2tsv', - '../third_party/pdfium/samples/samples.gyp:pdfium_diff', - '../third_party/webrtc/tools/tools.gyp:frame_analyzer', - '../third_party/webrtc/tools/tools.gyp:rgba_to_i420_converter', '../tools/win/static_initializers/static_initializers.gyp:static_initializers', ], }], @@ -630,6 +628,7 @@ }], ['OS=="win" and target_arch=="ia32"', { 'dependencies': [ + # TODO(GYP): All of these targets need to be ported over. '../base/base.gyp:base_win64', '../base/base.gyp:base_i18n_nacl_win64', '../chrome/chrome.gyp:crash_service_win64', @@ -645,6 +644,7 @@ }], ['OS=="win" and target_arch=="ia32" and configuration_policy==1', { 'dependencies': [ + # TODO(GYP): All of these targets need to be ported over. '../components/components.gyp:policy_win64', ] }], @@ -667,6 +667,17 @@ 'chromium_gpu_builder', 'chromium_gpu_debug_builder', ], + 'conditions': [ + ['OS=="win"', { + 'dependencies': [ + 'chromium_builder', + 'chromium_builder_dbg_drmemory_win', + 'chromium_builder_nacl_sdk', + 'chromium_builder_lkgr_drmemory_win', + 'chromium_builder_dbg_tsan_win', + ], + }], + ], }, ] }
diff --git a/build/ios/grit_whitelist.txt b/build/ios/grit_whitelist.txt index b33b2ea..b724a99 100644 --- a/build/ios/grit_whitelist.txt +++ b/build/ios/grit_whitelist.txt
@@ -100,7 +100,7 @@ IDR_TOOLBAR_SHADOW_FULL_BLEED IDR_TRANSLATE_JS IDR_UBER_UTILS_JS -IDR_WEBUI_I18N_TEMPLATE2_JS +IDR_WEBUI_I18N_TEMPLATE_JS IDR_WEBUI_I18N_TEMPLATE_POLYMER_JS IDR_WEBUI_JSTEMPLATE_JS IDR_WEBUI_JS_LOAD_TIME_DATA
diff --git a/cc/base/unique_notifier_unittest.cc b/cc/base/unique_notifier_unittest.cc index dfab85e6..7b52512 100644 --- a/cc/base/unique_notifier_unittest.cc +++ b/cc/base/unique_notifier_unittest.cc
@@ -4,9 +4,9 @@ #include "base/bind.h" #include "base/bind_helpers.h" -#include "base/message_loop/message_loop_proxy.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" +#include "base/thread_task_runner_handle.h" #include "cc/base/unique_notifier.h" #include "testing/gtest/include/gtest/gtest.h" @@ -32,7 +32,7 @@ TEST_F(UniqueNotifierTest, Schedule) { { UniqueNotifier notifier( - base::MessageLoopProxy::current().get(), + base::ThreadTaskRunnerHandle::Get().get(), base::Bind(&UniqueNotifierTest::Notify, base::Unretained(this))); EXPECT_EQ(0, NotificationCount());
diff --git a/cc/debug/micro_benchmark.cc b/cc/debug/micro_benchmark.cc index 64629de..cf6e2698 100644 --- a/cc/debug/micro_benchmark.cc +++ b/cc/debug/micro_benchmark.cc
@@ -7,7 +7,7 @@ #include "base/callback.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop_proxy.h" +#include "base/single_thread_task_runner.h" #include "base/values.h" #include "cc/debug/micro_benchmark_impl.h" @@ -46,14 +46,14 @@ } scoped_ptr<MicroBenchmarkImpl> MicroBenchmark::GetBenchmarkImpl( - scoped_refptr<base::MessageLoopProxy> origin_loop) { + scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner) { DCHECK(!processed_for_benchmark_impl_); processed_for_benchmark_impl_ = true; - return CreateBenchmarkImpl(origin_loop); + return CreateBenchmarkImpl(origin_task_runner); } scoped_ptr<MicroBenchmarkImpl> MicroBenchmark::CreateBenchmarkImpl( - scoped_refptr<base::MessageLoopProxy> origin_loop) { + scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner) { return make_scoped_ptr<MicroBenchmarkImpl>(nullptr); }
diff --git a/cc/debug/micro_benchmark.h b/cc/debug/micro_benchmark.h index 1654c36..c5bbd88 100644 --- a/cc/debug/micro_benchmark.h +++ b/cc/debug/micro_benchmark.h
@@ -10,8 +10,8 @@ #include "cc/base/cc_export.h" namespace base { +class SingleThreadTaskRunner; class Value; -class MessageLoopProxy; } // namespace base namespace cc { @@ -39,13 +39,13 @@ bool ProcessedForBenchmarkImpl() const; scoped_ptr<MicroBenchmarkImpl> GetBenchmarkImpl( - scoped_refptr<base::MessageLoopProxy> origin_loop); + scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner); protected: void NotifyDone(scoped_ptr<base::Value> result); virtual scoped_ptr<MicroBenchmarkImpl> CreateBenchmarkImpl( - scoped_refptr<base::MessageLoopProxy> origin_loop); + scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner); private: DoneCallback callback_;
diff --git a/cc/debug/micro_benchmark_controller.cc b/cc/debug/micro_benchmark_controller.cc index bf98100..a38e5ad 100644 --- a/cc/debug/micro_benchmark_controller.cc +++ b/cc/debug/micro_benchmark_controller.cc
@@ -8,7 +8,7 @@ #include <string> #include "base/callback.h" -#include "base/message_loop/message_loop_proxy.h" +#include "base/thread_task_runner_handle.h" #include "base/values.h" #include "cc/debug/invalidation_benchmark.h" #include "cc/debug/picture_record_benchmark.h" @@ -54,7 +54,9 @@ MicroBenchmarkController::MicroBenchmarkController(LayerTreeHost* host) : host_(host), - main_controller_message_loop_(base::MessageLoopProxy::current().get()) { + main_controller_task_runner_(base::ThreadTaskRunnerHandle::IsSet() + ? base::ThreadTaskRunnerHandle::Get() + : nullptr) { DCHECK(host_); } @@ -102,8 +104,7 @@ ++it) { scoped_ptr<MicroBenchmarkImpl> benchmark_impl; if (!(*it)->ProcessedForBenchmarkImpl()) { - benchmark_impl = - (*it)->GetBenchmarkImpl(main_controller_message_loop_); + benchmark_impl = (*it)->GetBenchmarkImpl(main_controller_task_runner_); } if (benchmark_impl.get())
diff --git a/cc/debug/micro_benchmark_controller.h b/cc/debug/micro_benchmark_controller.h index 88f6d9ad..198e203f 100644 --- a/cc/debug/micro_benchmark_controller.h +++ b/cc/debug/micro_benchmark_controller.h
@@ -13,8 +13,8 @@ #include "cc/debug/micro_benchmark.h" namespace base { +class SingleThreadTaskRunner; class Value; -class MessageLoopProxy; } // namespace base namespace cc { @@ -44,7 +44,7 @@ LayerTreeHost* host_; ScopedPtrVector<MicroBenchmark> benchmarks_; static int next_id_; - scoped_refptr<base::MessageLoopProxy> main_controller_message_loop_; + scoped_refptr<base::SingleThreadTaskRunner> main_controller_task_runner_; DISALLOW_COPY_AND_ASSIGN(MicroBenchmarkController); };
diff --git a/cc/debug/micro_benchmark_impl.cc b/cc/debug/micro_benchmark_impl.cc index 7ec58c8..f20f32e 100644 --- a/cc/debug/micro_benchmark_impl.cc +++ b/cc/debug/micro_benchmark_impl.cc
@@ -6,8 +6,9 @@ #include "base/bind.h" #include "base/callback.h" +#include "base/location.h" #include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" +#include "base/single_thread_task_runner.h" #include "base/values.h" namespace cc { @@ -23,8 +24,11 @@ MicroBenchmarkImpl::MicroBenchmarkImpl( const DoneCallback& callback, - scoped_refptr<base::MessageLoopProxy> origin_loop) - : callback_(callback), is_done_(false), origin_loop_(origin_loop) {} + scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner) + : callback_(callback), + is_done_(false), + origin_task_runner_(origin_task_runner) { +} MicroBenchmarkImpl::~MicroBenchmarkImpl() {} @@ -35,9 +39,8 @@ void MicroBenchmarkImpl::DidCompleteCommit(LayerTreeHostImpl* host) {} void MicroBenchmarkImpl::NotifyDone(scoped_ptr<base::Value> result) { - origin_loop_->PostTask( - FROM_HERE, - base::Bind(RunCallback, callback_, base::Passed(&result))); + origin_task_runner_->PostTask( + FROM_HERE, base::Bind(RunCallback, callback_, base::Passed(&result))); is_done_ = true; }
diff --git a/cc/debug/micro_benchmark_impl.h b/cc/debug/micro_benchmark_impl.h index 4f3f74f..ed968a39 100644 --- a/cc/debug/micro_benchmark_impl.h +++ b/cc/debug/micro_benchmark_impl.h
@@ -10,8 +10,8 @@ #include "cc/base/cc_export.h" namespace base { +class SingleThreadTaskRunner; class Value; -class MessageLoopProxy; } // namespace base namespace cc { @@ -25,7 +25,7 @@ explicit MicroBenchmarkImpl( const DoneCallback& callback, - scoped_refptr<base::MessageLoopProxy> origin_loop); + scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner); virtual ~MicroBenchmarkImpl(); bool IsDone() const; @@ -40,7 +40,7 @@ private: DoneCallback callback_; bool is_done_; - scoped_refptr<base::MessageLoopProxy> origin_loop_; + scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_; }; } // namespace cc
diff --git a/cc/debug/rasterize_and_record_benchmark.cc b/cc/debug/rasterize_and_record_benchmark.cc index 54f48f3b8..ab05f30 100644 --- a/cc/debug/rasterize_and_record_benchmark.cc +++ b/cc/debug/rasterize_and_record_benchmark.cc
@@ -94,10 +94,9 @@ } scoped_ptr<MicroBenchmarkImpl> RasterizeAndRecordBenchmark::CreateBenchmarkImpl( - scoped_refptr<base::MessageLoopProxy> origin_loop) { + scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner) { return make_scoped_ptr(new RasterizeAndRecordBenchmarkImpl( - origin_loop, - settings_.get(), + origin_task_runner, settings_.get(), base::Bind(&RasterizeAndRecordBenchmark::RecordRasterResults, weak_ptr_factory_.GetWeakPtr()))); }
diff --git a/cc/debug/rasterize_and_record_benchmark.h b/cc/debug/rasterize_and_record_benchmark.h index 46f106fb..9215f2df 100644 --- a/cc/debug/rasterize_and_record_benchmark.h +++ b/cc/debug/rasterize_and_record_benchmark.h
@@ -10,6 +10,7 @@ #include <vector> #include "base/memory/weak_ptr.h" +#include "base/single_thread_task_runner.h" #include "base/time/time.h" #include "cc/debug/micro_benchmark_controller.h" #include "cc/resources/picture.h" @@ -34,7 +35,7 @@ void RunOnLayer(PictureLayer* layer) override; scoped_ptr<MicroBenchmarkImpl> CreateBenchmarkImpl( - scoped_refptr<base::MessageLoopProxy> origin_loop) override; + scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner) override; private: void RunOnDisplayListLayer(PictureLayer* layer,
diff --git a/cc/debug/rasterize_and_record_benchmark_impl.cc b/cc/debug/rasterize_and_record_benchmark_impl.cc index 443db8c..3049103 100644 --- a/cc/debug/rasterize_and_record_benchmark_impl.cc +++ b/cc/debug/rasterize_and_record_benchmark_impl.cc
@@ -113,10 +113,10 @@ } // namespace RasterizeAndRecordBenchmarkImpl::RasterizeAndRecordBenchmarkImpl( - scoped_refptr<base::MessageLoopProxy> origin_loop, + scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner, base::Value* value, const MicroBenchmarkImpl::DoneCallback& callback) - : MicroBenchmarkImpl(callback, origin_loop), + : MicroBenchmarkImpl(callback, origin_task_runner), rasterize_repeat_count_(kDefaultRasterizeRepeatCount) { base::DictionaryValue* settings = nullptr; value->GetAsDictionary(&settings);
diff --git a/cc/debug/rasterize_and_record_benchmark_impl.h b/cc/debug/rasterize_and_record_benchmark_impl.h index ae134ab2..06224da 100644 --- a/cc/debug/rasterize_and_record_benchmark_impl.h +++ b/cc/debug/rasterize_and_record_benchmark_impl.h
@@ -9,6 +9,7 @@ #include <utility> #include <vector> +#include "base/single_thread_task_runner.h" #include "base/time/time.h" #include "cc/debug/micro_benchmark_impl.h" #include "cc/resources/task_graph_runner.h" @@ -21,7 +22,7 @@ class RasterizeAndRecordBenchmarkImpl : public MicroBenchmarkImpl { public: explicit RasterizeAndRecordBenchmarkImpl( - scoped_refptr<base::MessageLoopProxy> origin_loop, + scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner, base::Value* value, const MicroBenchmarkImpl::DoneCallback& callback); ~RasterizeAndRecordBenchmarkImpl() override;
diff --git a/cc/debug/unittest_only_benchmark.cc b/cc/debug/unittest_only_benchmark.cc index 2bd5be9..81158122 100644 --- a/cc/debug/unittest_only_benchmark.cc +++ b/cc/debug/unittest_only_benchmark.cc
@@ -5,7 +5,7 @@ #include "cc/debug/unittest_only_benchmark.h" #include "base/bind.h" -#include "base/message_loop/message_loop_proxy.h" +#include "base/single_thread_task_runner.h" #include "base/values.h" #include "cc/debug/unittest_only_benchmark_impl.h" @@ -53,13 +53,12 @@ } scoped_ptr<MicroBenchmarkImpl> UnittestOnlyBenchmark::CreateBenchmarkImpl( - scoped_refptr<base::MessageLoopProxy> origin_loop) { + scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner) { if (!create_impl_benchmark_) return make_scoped_ptr<MicroBenchmarkImpl>(nullptr); return make_scoped_ptr(new UnittestOnlyBenchmarkImpl( - origin_loop, - nullptr, + origin_task_runner, nullptr, base::Bind(&UnittestOnlyBenchmark::RecordImplResults, weak_ptr_factory_.GetWeakPtr()))); }
diff --git a/cc/debug/unittest_only_benchmark.h b/cc/debug/unittest_only_benchmark.h index 7fa2b4dc..4e74ec7 100644 --- a/cc/debug/unittest_only_benchmark.h +++ b/cc/debug/unittest_only_benchmark.h
@@ -8,6 +8,10 @@ #include "base/memory/weak_ptr.h" #include "cc/debug/micro_benchmark.h" +namespace base { +class SingleThreadIdleTaskRunner; +} + namespace cc { class CC_EXPORT UnittestOnlyBenchmark : public MicroBenchmark { @@ -21,7 +25,7 @@ protected: scoped_ptr<MicroBenchmarkImpl> CreateBenchmarkImpl( - scoped_refptr<base::MessageLoopProxy> origin_loop) override; + scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner) override; private: void RecordImplResults(scoped_ptr<base::Value> results);
diff --git a/cc/debug/unittest_only_benchmark_impl.cc b/cc/debug/unittest_only_benchmark_impl.cc index a3b040f..59e3d27 100644 --- a/cc/debug/unittest_only_benchmark_impl.cc +++ b/cc/debug/unittest_only_benchmark_impl.cc
@@ -4,16 +4,17 @@ #include "cc/debug/unittest_only_benchmark_impl.h" -#include "base/message_loop/message_loop_proxy.h" +#include "base/single_thread_task_runner.h" #include "base/values.h" namespace cc { UnittestOnlyBenchmarkImpl::UnittestOnlyBenchmarkImpl( - scoped_refptr<base::MessageLoopProxy> origin_loop, + scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner, base::Value* settings, const DoneCallback& callback) - : MicroBenchmarkImpl(callback, origin_loop) {} + : MicroBenchmarkImpl(callback, origin_task_runner) { +} UnittestOnlyBenchmarkImpl::~UnittestOnlyBenchmarkImpl() {}
diff --git a/cc/debug/unittest_only_benchmark_impl.h b/cc/debug/unittest_only_benchmark_impl.h index f9b256d..1444850 100644 --- a/cc/debug/unittest_only_benchmark_impl.h +++ b/cc/debug/unittest_only_benchmark_impl.h
@@ -9,8 +9,8 @@ #include "cc/debug/micro_benchmark_impl.h" namespace base { +class SingleThreadTaskRunner; class Value; -class MessageLoopProxy; } namespace cc { @@ -18,9 +18,10 @@ class LayerTreeHostImpl; class CC_EXPORT UnittestOnlyBenchmarkImpl : public MicroBenchmarkImpl { public: - UnittestOnlyBenchmarkImpl(scoped_refptr<base::MessageLoopProxy> origin_loop, - base::Value* settings, - const DoneCallback& callback); + UnittestOnlyBenchmarkImpl( + scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner, + base::Value* settings, + const DoneCallback& callback); ~UnittestOnlyBenchmarkImpl() override; void DidCompleteCommit(LayerTreeHostImpl* host) override;
diff --git a/cc/layers/delegated_frame_resource_collection_unittest.cc b/cc/layers/delegated_frame_resource_collection_unittest.cc index f91fe63..e5426a0 100644 --- a/cc/layers/delegated_frame_resource_collection_unittest.cc +++ b/cc/layers/delegated_frame_resource_collection_unittest.cc
@@ -3,8 +3,11 @@ // found in the LICENSE file. #include "base/bind.h" +#include "base/location.h" #include "base/run_loop.h" +#include "base/single_thread_task_runner.h" #include "base/synchronization/waitable_event.h" +#include "base/thread_task_runner_handle.h" #include "base/threading/thread.h" #include "cc/layers/delegated_frame_resource_collection.h" #include "cc/resources/returned_resource.h" @@ -95,7 +98,7 @@ base::Thread thread("test thread"); thread.Start(); scoped_ptr<BlockingTaskRunner> main_thread_task_runner( - BlockingTaskRunner::Create(base::MessageLoopProxy::current())); + BlockingTaskRunner::Create(base::ThreadTaskRunnerHandle::Get())); TransferableResourceArray resources = CreateResourceArray(); resource_collection_->ReceivedResources(resources); @@ -110,14 +113,12 @@ base::RunLoop run_loop; resources_available_closure_ = run_loop.QuitClosure(); - thread.message_loop()->PostTask( + thread.message_loop()->task_runner()->PostTask( FROM_HERE, base::Bind( &ReturnResourcesOnThread, resource_collection_->GetReturnResourcesCallbackForImplThread(), - returned_resources, - &event, - main_thread_task_runner.get())); + returned_resources, &event, main_thread_task_runner.get())); run_loop.Run(); } @@ -152,12 +153,10 @@ returned_resources_.clear(); base::WaitableEvent* null_event = nullptr; - thread.message_loop()->PostTask(FROM_HERE, - base::Bind(&ReturnResourcesOnThread, - return_callback, - returned_resources, - null_event, - main_thread_task_runner.get())); + thread.message_loop()->task_runner()->PostTask( + FROM_HERE, + base::Bind(&ReturnResourcesOnThread, return_callback, returned_resources, + null_event, main_thread_task_runner.get())); thread.Stop(); }
diff --git a/cc/layers/layer_perftest.cc b/cc/layers/layer_perftest.cc index 72b2e134..c7cac01f 100644 --- a/cc/layers/layer_perftest.cc +++ b/cc/layers/layer_perftest.cc
@@ -4,6 +4,7 @@ #include "cc/layers/layer.h" +#include "base/thread_task_runner_handle.h" #include "cc/debug/lap_timer.h" #include "cc/resources/layer_painter.h" #include "cc/test/fake_impl_proxy.h" @@ -40,7 +41,7 @@ void SetUp() override { layer_tree_host_ = FakeLayerTreeHost::Create(&fake_client_); layer_tree_host_->InitializeSingleThreaded( - &fake_client_, base::MessageLoopProxy::current(), nullptr); + &fake_client_, base::ThreadTaskRunnerHandle::Get(), nullptr); } void TearDown() override {
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc index 973c976..bae81850 100644 --- a/cc/layers/layer_unittest.cc +++ b/cc/layers/layer_unittest.cc
@@ -4,6 +4,7 @@ #include "cc/layers/layer.h" +#include "base/thread_task_runner_handle.h" #include "cc/animation/keyframed_animation_curve.h" #include "cc/base/math_util.h" #include "cc/layers/layer_impl.h" @@ -45,8 +46,7 @@ public: explicit MockLayerTreeHost(FakeLayerTreeHostClient* client) : LayerTreeHost(client, nullptr, nullptr, nullptr, LayerTreeSettings()) { - InitializeSingleThreaded(client, - base::MessageLoopProxy::current(), + InitializeSingleThreaded(client, base::ThreadTaskRunnerHandle::Get(), nullptr); } @@ -941,14 +941,14 @@ return LayerTreeHost::CreateSingleThreaded( &client_, &client_, shared_bitmap_manager_.get(), gpu_memory_buffer_manager_.get(), nullptr, LayerTreeSettings(), - base::MessageLoopProxy::current(), nullptr); + base::ThreadTaskRunnerHandle::Get(), nullptr); } scoped_ptr<LayerTreeHost> Create(LayerTreeSettings settings) { return LayerTreeHost::CreateSingleThreaded( &client_, &client_, shared_bitmap_manager_.get(), gpu_memory_buffer_manager_.get(), nullptr, settings, - base::MessageLoopProxy::current(), nullptr); + base::ThreadTaskRunnerHandle::Get(), nullptr); } private:
diff --git a/cc/layers/picture_image_layer_impl_unittest.cc b/cc/layers/picture_image_layer_impl_unittest.cc index 87c4e58..5814bb4 100644 --- a/cc/layers/picture_image_layer_impl_unittest.cc +++ b/cc/layers/picture_image_layer_impl_unittest.cc
@@ -4,6 +4,7 @@ #include "cc/layers/picture_image_layer_impl.h" +#include "base/thread_task_runner_handle.h" #include "cc/layers/append_quads_data.h" #include "cc/quads/draw_quad.h" #include "cc/resources/tile_priority.h" @@ -35,7 +36,7 @@ class PictureImageLayerImplTest : public testing::Test { public: PictureImageLayerImplTest() - : proxy_(base::MessageLoopProxy::current()), + : proxy_(base::ThreadTaskRunnerHandle::Get()), host_impl_(ImplSidePaintingSettings(), &proxy_, &shared_bitmap_manager_,
diff --git a/cc/layers/picture_layer_impl_perftest.cc b/cc/layers/picture_layer_impl_perftest.cc index 5369638..9ad6a24 100644 --- a/cc/layers/picture_layer_impl_perftest.cc +++ b/cc/layers/picture_layer_impl_perftest.cc
@@ -4,6 +4,7 @@ #include "cc/layers/picture_layer_impl.h" +#include "base/thread_task_runner_handle.h" #include "cc/debug/lap_timer.h" #include "cc/resources/tiling_set_raster_queue_all.h" #include "cc/test/fake_impl_proxy.h" @@ -39,7 +40,7 @@ class PictureLayerImplPerfTest : public testing::Test { public: PictureLayerImplPerfTest() - : proxy_(base::MessageLoopProxy::current()), + : proxy_(base::ThreadTaskRunnerHandle::Get()), host_impl_(ImplSidePaintingSettings(), &proxy_, &shared_bitmap_manager_,
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc index 4db0f5b5f..966186f 100644 --- a/cc/layers/picture_layer_impl_unittest.cc +++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -9,6 +9,8 @@ #include <set> #include <utility> +#include "base/location.h" +#include "base/thread_task_runner_handle.h" #include "cc/base/math_util.h" #include "cc/layers/append_quads_data.h" #include "cc/layers/picture_layer.h" @@ -71,7 +73,7 @@ class PictureLayerImplTest : public testing::Test { public: PictureLayerImplTest() - : proxy_(base::MessageLoopProxy::current()), + : proxy_(base::ThreadTaskRunnerHandle::Get()), host_impl_(LowResTilingsSettings(), &proxy_, &shared_bitmap_manager_, @@ -85,7 +87,7 @@ } explicit PictureLayerImplTest(const LayerTreeSettings& settings) - : proxy_(base::MessageLoopProxy::current()), + : proxy_(base::ThreadTaskRunnerHandle::Get()), host_impl_(settings, &proxy_, &shared_bitmap_manager_,
diff --git a/cc/layers/picture_layer_unittest.cc b/cc/layers/picture_layer_unittest.cc index 48d4abc..2f64693 100644 --- a/cc/layers/picture_layer_unittest.cc +++ b/cc/layers/picture_layer_unittest.cc
@@ -4,6 +4,7 @@ #include "cc/layers/picture_layer.h" +#include "base/thread_task_runner_handle.h" #include "cc/layers/content_layer_client.h" #include "cc/layers/picture_layer_impl.h" #include "cc/resources/resource_update_queue.h" @@ -130,12 +131,12 @@ scoped_ptr<LayerTreeHost> host1 = LayerTreeHost::CreateSingleThreaded( &host_client1, &host_client1, shared_bitmap_manager.get(), nullptr, - nullptr, settings, base::MessageLoopProxy::current(), nullptr); + nullptr, settings, base::ThreadTaskRunnerHandle::Get(), nullptr); host_client1.SetLayerTreeHost(host1.get()); scoped_ptr<LayerTreeHost> host2 = LayerTreeHost::CreateSingleThreaded( &host_client2, &host_client2, shared_bitmap_manager.get(), nullptr, - nullptr, settings, base::MessageLoopProxy::current(), nullptr); + nullptr, settings, base::ThreadTaskRunnerHandle::Get(), nullptr); host_client2.SetLayerTreeHost(host2.get()); // The PictureLayer is put in one LayerTreeHost.
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc index 009ec3b7..cee0c9b 100644 --- a/cc/layers/scrollbar_layer_unittest.cc +++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/containers/hash_tables.h" +#include "base/thread_task_runner_handle.h" #include "cc/animation/scrollbar_animation_controller.h" #include "cc/layers/append_quads_data.h" #include "cc/layers/painted_scrollbar_layer.h" @@ -68,7 +69,7 @@ next_id_(1), total_ui_resource_created_(0), total_ui_resource_deleted_(0) { - InitializeSingleThreaded(client, base::MessageLoopProxy::current(), + InitializeSingleThreaded(client, base::ThreadTaskRunnerHandle::Get(), nullptr); }
diff --git a/cc/layers/surface_layer_unittest.cc b/cc/layers/surface_layer_unittest.cc index 285acee..6661a1a2 100644 --- a/cc/layers/surface_layer_unittest.cc +++ b/cc/layers/surface_layer_unittest.cc
@@ -5,7 +5,9 @@ #include <set> #include <vector> -#include "base/message_loop/message_loop_proxy.h" +#include "base/location.h" +#include "base/single_thread_task_runner.h" +#include "base/thread_task_runner_handle.h" #include "cc/layers/solid_color_layer.h" #include "cc/layers/surface_layer.h" #include "cc/test/fake_impl_proxy.h" @@ -173,7 +175,7 @@ } void DidCommitAndDrawFrame() override { - base::MessageLoopProxy::current()->PostTask( + base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&SurfaceLayerSwapPromise::ChangeTree, base::Unretained(this))); }
diff --git a/cc/layers/texture_layer_unittest.cc b/cc/layers/texture_layer_unittest.cc index b088f6f..3bd90ec 100644 --- a/cc/layers/texture_layer_unittest.cc +++ b/cc/layers/texture_layer_unittest.cc
@@ -9,7 +9,10 @@ #include "base/bind.h" #include "base/callback.h" +#include "base/location.h" +#include "base/single_thread_task_runner.h" #include "base/synchronization/waitable_event.h" +#include "base/thread_task_runner_handle.h" #include "base/threading/thread.h" #include "base/time/time.h" #include "cc/layers/solid_color_layer.h" @@ -53,8 +56,7 @@ public: explicit MockLayerTreeHost(FakeLayerTreeHostClient* client) : LayerTreeHost(client, nullptr, nullptr, nullptr, LayerTreeSettings()) { - InitializeSingleThreaded(client, - base::MessageLoopProxy::current(), + InitializeSingleThreaded(client, base::ThreadTaskRunnerHandle::Get(), nullptr); } @@ -403,10 +405,9 @@ TextureLayerMailboxHolderTest() : main_thread_("MAIN") { main_thread_.Start(); - main_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&TextureLayerMailboxHolderTest::InitializeOnMain, - base::Unretained(this))); + main_thread_.message_loop()->task_runner()->PostTask( + FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::InitializeOnMain, + base::Unretained(this))); Wait(main_thread_); } @@ -414,7 +415,7 @@ bool manual_reset = false; bool initially_signaled = false; base::WaitableEvent event(manual_reset, initially_signaled); - thread.message_loop()->PostTask( + thread.message_loop()->task_runner()->PostTask( FROM_HERE, base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event))); event.Wait(); @@ -445,7 +446,7 @@ protected: void InitializeOnMain() { main_thread_task_runner_ = - BlockingTaskRunner::Create(main_thread_.message_loop_proxy()); + BlockingTaskRunner::Create(main_thread_.task_runner()); } scoped_ptr<TestMailboxHolder::MainThreadReference> @@ -459,30 +460,25 @@ TextureLayer::CreateForMailbox(nullptr); ASSERT_TRUE(test_layer.get()); - main_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef, - base::Unretained(this))); + main_thread_.message_loop()->task_runner()->PostTask( + FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef, + base::Unretained(this))); Wait(main_thread_); // The texture layer is attached to compositor1, and passes a reference to its // impl tree. scoped_ptr<SingleReleaseCallbackImpl> compositor1; - main_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef, - base::Unretained(this), - &compositor1)); + main_thread_.message_loop()->task_runner()->PostTask( + FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef, + base::Unretained(this), &compositor1)); // Then the texture layer is removed and attached to compositor2, and passes a // reference to its impl tree. scoped_ptr<SingleReleaseCallbackImpl> compositor2; - main_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef, - base::Unretained(this), - &compositor2)); + main_thread_.message_loop()->task_runner()->PostTask( + FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef, + base::Unretained(this), &compositor2)); Wait(main_thread_); Mock::VerifyAndClearExpectations(&test_data_.mock_callback_); @@ -502,10 +498,9 @@ EXPECT_CALL(test_data_.mock_callback_, Release(test_data_.mailbox_name1_, 200, false)).Times(1); - main_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef, - base::Unretained(this))); + main_thread_.message_loop()->task_runner()->PostTask( + FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef, + base::Unretained(this))); Wait(main_thread_); Mock::VerifyAndClearExpectations(&test_data_.mock_callback_); } @@ -515,30 +510,25 @@ TextureLayer::CreateForMailbox(nullptr); ASSERT_TRUE(test_layer.get()); - main_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef, - base::Unretained(this))); + main_thread_.message_loop()->task_runner()->PostTask( + FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef, + base::Unretained(this))); Wait(main_thread_); // The texture layer is attached to compositor1, and passes a reference to its // impl tree. scoped_ptr<SingleReleaseCallbackImpl> compositor1; - main_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef, - base::Unretained(this), - &compositor1)); + main_thread_.message_loop()->task_runner()->PostTask( + FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef, + base::Unretained(this), &compositor1)); // Then the texture layer is removed and attached to compositor2, and passes a // reference to its impl tree. scoped_ptr<SingleReleaseCallbackImpl> compositor2; - main_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef, - base::Unretained(this), - &compositor2)); + main_thread_.message_loop()->task_runner()->PostTask( + FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef, + base::Unretained(this), &compositor2)); Wait(main_thread_); Mock::VerifyAndClearExpectations(&test_data_.mock_callback_); @@ -547,10 +537,9 @@ compositor1->Run(100, false, main_thread_task_runner_.get()); // Then the main thread reference is destroyed. - main_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef, - base::Unretained(this))); + main_thread_.message_loop()->task_runner()->PostTask( + FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef, + base::Unretained(this))); Wait(main_thread_); @@ -572,39 +561,33 @@ TextureLayer::CreateForMailbox(nullptr); ASSERT_TRUE(test_layer.get()); - main_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef, - base::Unretained(this))); + main_thread_.message_loop()->task_runner()->PostTask( + FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef, + base::Unretained(this))); Wait(main_thread_); // The texture layer is attached to compositor1, and passes a reference to its // impl tree. scoped_ptr<SingleReleaseCallbackImpl> compositor1; - main_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef, - base::Unretained(this), - &compositor1)); + main_thread_.message_loop()->task_runner()->PostTask( + FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef, + base::Unretained(this), &compositor1)); // Then the texture layer is removed and attached to compositor2, and passes a // reference to its impl tree. scoped_ptr<SingleReleaseCallbackImpl> compositor2; - main_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef, - base::Unretained(this), - &compositor2)); + main_thread_.message_loop()->task_runner()->PostTask( + FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef, + base::Unretained(this), &compositor2)); Wait(main_thread_); Mock::VerifyAndClearExpectations(&test_data_.mock_callback_); // The main thread reference is destroyed first. - main_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef, - base::Unretained(this))); + main_thread_.message_loop()->task_runner()->PostTask( + FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef, + base::Unretained(this))); // One compositor destroys their impl tree. compositor2->Run(200, false, main_thread_task_runner_.get()); @@ -629,39 +612,33 @@ TextureLayer::CreateForMailbox(nullptr); ASSERT_TRUE(test_layer.get()); - main_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef, - base::Unretained(this))); + main_thread_.message_loop()->task_runner()->PostTask( + FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef, + base::Unretained(this))); Wait(main_thread_); // The texture layer is attached to compositor1, and passes a reference to its // impl tree. scoped_ptr<SingleReleaseCallbackImpl> compositor1; - main_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef, - base::Unretained(this), - &compositor1)); + main_thread_.message_loop()->task_runner()->PostTask( + FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef, + base::Unretained(this), &compositor1)); // Then the texture layer is removed and attached to compositor2, and passes a // reference to its impl tree. scoped_ptr<SingleReleaseCallbackImpl> compositor2; - main_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef, - base::Unretained(this), - &compositor2)); + main_thread_.message_loop()->task_runner()->PostTask( + FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef, + base::Unretained(this), &compositor2)); Wait(main_thread_); Mock::VerifyAndClearExpectations(&test_data_.mock_callback_); // The main thread reference is destroyed first. - main_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef, - base::Unretained(this))); + main_thread_.message_loop()->task_runner()->PostTask( + FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef, + base::Unretained(this))); EXPECT_CALL(test_data_.mock_callback_, Release(test_data_.mailbox_name1_, 200, true)).Times(1); @@ -674,12 +651,10 @@ // Post a task to start capturing tasks on the main thread. This will block // the main thread until we signal the |stop_capture| event. - main_thread_.message_loop()->PostTask( + main_thread_.message_loop()->task_runner()->PostTask( FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CapturePostTasksAndWait, - base::Unretained(this), - &begin_capture, - &wait_for_capture, + base::Unretained(this), &begin_capture, &wait_for_capture, &stop_capture)); // Before the main thread capturing starts, one compositor destroys their
diff --git a/cc/layers/tiled_layer_unittest.cc b/cc/layers/tiled_layer_unittest.cc index 511df0a..b81e031 100644 --- a/cc/layers/tiled_layer_unittest.cc +++ b/cc/layers/tiled_layer_unittest.cc
@@ -7,7 +7,10 @@ #include <limits> #include <vector> +#include "base/location.h" #include "base/run_loop.h" +#include "base/single_thread_task_runner.h" +#include "base/thread_task_runner_handle.h" #include "cc/resources/bitmap_content_layer_updater.h" #include "cc/resources/layer_painter.h" #include "cc/resources/prioritized_resource_manager.h" @@ -51,10 +54,8 @@ : FakeLayerTreeHostClient(FakeLayerTreeHostClient::DIRECT_3D) {} bool EnsureOutputSurfaceCreated() { - base::MessageLoop::current()->PostDelayedTask( - FROM_HERE, - run_loop_.QuitClosure(), - base::TimeDelta::FromSeconds(5)); + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, run_loop_.QuitClosure(), base::TimeDelta::FromSeconds(5)); run_loop_.Run(); return output_surface_created_; } @@ -95,8 +96,8 @@ shared_bitmap_manager_.reset(new TestSharedBitmapManager()); layer_tree_host_ = LayerTreeHost::CreateThreaded( &synchonous_output_surface_client_, shared_bitmap_manager_.get(), - nullptr, nullptr, settings_, base::MessageLoopProxy::current(), - impl_thread_.message_loop_proxy(), nullptr); + nullptr, nullptr, settings_, base::ThreadTaskRunnerHandle::Get(), + impl_thread_.task_runner(), nullptr); synchonous_output_surface_client_.SetLayerTreeHost(layer_tree_host_.get()); proxy_ = layer_tree_host_->proxy(); resource_manager_ = PrioritizedResourceManager::Create(proxy_);
diff --git a/cc/layers/ui_resource_layer_unittest.cc b/cc/layers/ui_resource_layer_unittest.cc index a8cf77e..d0d356d 100644 --- a/cc/layers/ui_resource_layer_unittest.cc +++ b/cc/layers/ui_resource_layer_unittest.cc
@@ -4,6 +4,7 @@ #include "cc/layers/ui_resource_layer.h" +#include "base/thread_task_runner_handle.h" #include "cc/resources/prioritized_resource_manager.h" #include "cc/resources/resource_provider.h" #include "cc/resources/resource_update_queue.h" @@ -53,9 +54,7 @@ void SetUp() override { layer_tree_host_ = FakeLayerTreeHost::Create(&fake_client_); layer_tree_host_->InitializeSingleThreaded( - &fake_client_, - base::MessageLoopProxy::current(), - nullptr); + &fake_client_, base::ThreadTaskRunnerHandle::Get(), nullptr); } void TearDown() override {
diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc index 7e0f8e0f5..57c8481 100644 --- a/cc/output/gl_renderer_unittest.cc +++ b/cc/output/gl_renderer_unittest.cc
@@ -6,6 +6,9 @@ #include <set> +#include "base/location.h" +#include "base/single_thread_task_runner.h" +#include "base/thread_task_runner_handle.h" #include "cc/base/math_util.h" #include "cc/output/compositor_frame_metadata.h" #include "cc/resources/resource_provider.h" @@ -2032,7 +2035,7 @@ // Make the sync point happen. gl->Finish(); // Post a task after the sync point. - base::MessageLoop::current()->PostTask( + base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&OtherCallback, &other_callback_count)); base::MessageLoop::current()->Run(); @@ -2061,7 +2064,7 @@ // Make the sync point happen. gl->Finish(); // Post a task after the sync point. - base::MessageLoop::current()->PostTask( + base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&OtherCallback, &other_callback_count)); base::MessageLoop::current()->Run();
diff --git a/cc/output/output_surface.cc b/cc/output/output_surface.cc index c91352a4..5a6459c 100644 --- a/cc/output/output_surface.cc +++ b/cc/output/output_surface.cc
@@ -5,7 +5,9 @@ #include "cc/output/output_surface.h" #include "base/bind.h" -#include "base/message_loop/message_loop.h" +#include "base/location.h" +#include "base/single_thread_task_runner.h" +#include "base/thread_task_runner_handle.h" #include "base/trace_event/trace_event.h" #include "cc/output/managed_memory_policy.h" #include "cc/output/output_surface_client.h" @@ -182,10 +184,9 @@ } void OutputSurface::PostSwapBuffersComplete() { - base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&OutputSurface::OnSwapBuffersComplete, - weak_ptr_factory_.GetWeakPtr())); + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&OutputSurface::OnSwapBuffersComplete, + weak_ptr_factory_.GetWeakPtr())); } // We don't post tasks bound to the client directly since they might run
diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc index 2f3de43..df3a69a5 100644 --- a/cc/output/software_renderer.cc +++ b/cc/output/software_renderer.cc
@@ -236,8 +236,6 @@ return false; case ResourceProvider::RESOURCE_TYPE_BITMAP: return true; - case ResourceProvider::RESOURCE_TYPE_INVALID: - break; } LOG(FATAL) << "Invalid resource type.";
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc index 6f634a9..996370d 100644 --- a/cc/resources/resource_provider.cc +++ b/cc/resources/resource_provider.cc
@@ -243,43 +243,6 @@ } // namespace -ResourceProvider::Resource::Resource() - : child_id(0), - gl_id(0), - gl_pixel_buffer_id(0), - gl_upload_query_id(0), - gl_read_lock_query_id(0), - pixels(NULL), - lock_for_read_count(0), - imported_count(0), - exported_count(0), - dirty_image(false), - locked_for_write(false), - lost(false), - marked_for_deletion(false), - pending_set_pixels(false), - set_pixels_completion_forced(false), - allocated(false), - read_lock_fences_enabled(false), - has_shared_bitmap_id(false), - allow_overlay(false), - read_lock_fence(NULL), - size(), - origin(INTERNAL), - target(0), - original_filter(0), - filter(0), - image_id(0), - bound_image_id(0), - texture_pool(0), - wrap_mode(0), - hint(TEXTURE_HINT_IMMUTABLE), - type(RESOURCE_TYPE_INVALID), - format(RGBA_8888), - shared_bitmap(NULL), - gpu_memory_buffer(NULL) { -} - ResourceProvider::Resource::~Resource() {} ResourceProvider::Resource::Resource(GLuint texture_id, @@ -418,7 +381,9 @@ DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT); } -ResourceProvider::Child::Child() : marked_for_deletion(false) {} +ResourceProvider::Child::Child() + : marked_for_deletion(false), needs_sync_points(true) { +} ResourceProvider::Child::~Child() {} @@ -430,21 +395,23 @@ int highp_threshold_min, bool use_rgba_4444_texture_format, size_t id_allocation_chunk_size) { - scoped_ptr<ResourceProvider> resource_provider( - new ResourceProvider(output_surface, - shared_bitmap_manager, - gpu_memory_buffer_manager, - blocking_main_thread_task_runner, - highp_threshold_min, - use_rgba_4444_texture_format, - id_allocation_chunk_size)); + ContextProvider* context_provider = output_surface->context_provider(); + GLES2Interface* gl = + context_provider ? context_provider->ContextGL() : nullptr; + ResourceType default_resource_type = + gl ? RESOURCE_TYPE_GL_TEXTURE : RESOURCE_TYPE_BITMAP; - if (resource_provider->ContextGL()) + scoped_ptr<ResourceProvider> resource_provider(new ResourceProvider( + output_surface, shared_bitmap_manager, gpu_memory_buffer_manager, + blocking_main_thread_task_runner, highp_threshold_min, + default_resource_type, use_rgba_4444_texture_format, + id_allocation_chunk_size)); + + if (gl) resource_provider->InitializeGL(); else resource_provider->InitializeSoftware(); - DCHECK_NE(RESOURCE_TYPE_INVALID, resource_provider->default_resource_type()); return resource_provider.Pass(); } @@ -510,8 +477,6 @@ case RESOURCE_TYPE_BITMAP: DCHECK_EQ(RGBA_8888, format); return CreateBitmap(size, wrap_mode); - case RESOURCE_TYPE_INVALID: - break; } LOG(FATAL) << "Invalid default resource type."; @@ -536,8 +501,6 @@ case RESOURCE_TYPE_BITMAP: DCHECK_EQ(RGBA_8888, format); return CreateBitmap(size, wrap_mode); - case RESOURCE_TYPE_INVALID: - break; } LOG(FATAL) << "Invalid default resource type."; @@ -556,10 +519,10 @@ DCHECK(thread_checker_.CalledOnValidThread()); ResourceId id = next_id_++; - Resource resource(0, size, Resource::INTERNAL, target, GL_LINEAR, - texture_pool, wrap_mode, hint, format); - resource.allocated = false; - resources_[id] = resource; + Resource* resource = InsertResource( + id, Resource(0, size, Resource::INTERNAL, target, GL_LINEAR, texture_pool, + wrap_mode, hint, format)); + resource->allocated = false; return id; } @@ -573,10 +536,10 @@ DCHECK(pixels); ResourceId id = next_id_++; - Resource resource(pixels, bitmap.release(), size, Resource::INTERNAL, - GL_LINEAR, wrap_mode); - resource.allocated = true; - resources_[id] = resource; + Resource* resource = + InsertResource(id, Resource(pixels, bitmap.release(), size, + Resource::INTERNAL, GL_LINEAR, wrap_mode)); + resource->allocated = true; return id; } @@ -586,18 +549,17 @@ DCHECK(thread_checker_.CalledOnValidThread()); ResourceId id = next_id_++; - Resource resource(0, gfx::Size(), Resource::INTERNAL, - GL_TEXTURE_RECTANGLE_ARB, GL_LINEAR, - GL_TEXTURE_POOL_UNMANAGED_CHROMIUM, GL_CLAMP_TO_EDGE, - TEXTURE_HINT_IMMUTABLE, RGBA_8888); - LazyCreate(&resource); + Resource* resource = InsertResource( + id, Resource(0, gfx::Size(), Resource::INTERNAL, GL_TEXTURE_RECTANGLE_ARB, + GL_LINEAR, GL_TEXTURE_POOL_UNMANAGED_CHROMIUM, + GL_CLAMP_TO_EDGE, TEXTURE_HINT_IMMUTABLE, RGBA_8888)); + LazyCreate(resource); GLES2Interface* gl = ContextGL(); DCHECK(gl); - gl->BindTexture(GL_TEXTURE_RECTANGLE_ARB, resource.gl_id); + gl->BindTexture(GL_TEXTURE_RECTANGLE_ARB, resource->gl_id); gl->TexImageIOSurface2DCHROMIUM( GL_TEXTURE_RECTANGLE_ARB, size.width(), size.height(), io_surface_id, 0); - resource.allocated = true; - resources_[id] = resource; + resource->allocated = true; return id; } @@ -608,25 +570,27 @@ // Just store the information. Mailbox will be consumed in LockForRead(). ResourceId id = next_id_++; DCHECK(mailbox.IsValid()); - Resource& resource = resources_[id]; + Resource* resource = nullptr; if (mailbox.IsTexture()) { - resource = Resource(0, gfx::Size(), Resource::EXTERNAL, mailbox.target(), - mailbox.nearest_neighbor() ? GL_NEAREST : GL_LINEAR, 0, - GL_CLAMP_TO_EDGE, TEXTURE_HINT_IMMUTABLE, RGBA_8888); + resource = InsertResource( + id, Resource(0, gfx::Size(), Resource::EXTERNAL, mailbox.target(), + mailbox.nearest_neighbor() ? GL_NEAREST : GL_LINEAR, 0, + GL_CLAMP_TO_EDGE, TEXTURE_HINT_IMMUTABLE, RGBA_8888)); } else { DCHECK(mailbox.IsSharedMemory()); SharedBitmap* shared_bitmap = mailbox.shared_bitmap(); uint8_t* pixels = shared_bitmap->pixels(); DCHECK(pixels); - resource = Resource(pixels, shared_bitmap, mailbox.shared_memory_size(), - Resource::EXTERNAL, GL_LINEAR, GL_CLAMP_TO_EDGE); + resource = InsertResource( + id, Resource(pixels, shared_bitmap, mailbox.shared_memory_size(), + Resource::EXTERNAL, GL_LINEAR, GL_CLAMP_TO_EDGE)); } - resource.allocated = true; - resource.mailbox = mailbox; - resource.release_callback_impl = + resource->allocated = true; + resource->mailbox = mailbox; + resource->release_callback_impl = base::Bind(&SingleReleaseCallbackImpl::Run, base::Owned(release_callback_impl.release())); - resource.allow_overlay = mailbox.allow_overlay(); + resource->allow_overlay = mailbox.allow_overlay(); return id; } @@ -888,6 +852,15 @@ return gfx::FrameTime::Now() + upload_one_texture_time * total_uploads; } +ResourceProvider::Resource* ResourceProvider::InsertResource( + ResourceId id, + const Resource& resource) { + std::pair<ResourceMap::iterator, bool> result = + resources_.insert(ResourceMap::value_type(id, resource)); + DCHECK(result.second); + return &result.first->second; +} + ResourceProvider::Resource* ResourceProvider::GetResource(ResourceId id) { DCHECK(thread_checker_.CalledOnValidThread()); // TODO(danakj): crbug.com/455931 @@ -1223,6 +1196,7 @@ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, BlockingTaskRunner* blocking_main_thread_task_runner, int highp_threshold_min, + ResourceType default_resource_type, bool use_rgba_4444_texture_format, size_t id_allocation_chunk_size) : output_surface_(output_surface), @@ -1233,7 +1207,7 @@ highp_threshold_min_(highp_threshold_min), next_id_(1), next_child_(1), - default_resource_type_(RESOURCE_TYPE_INVALID), + default_resource_type_(default_resource_type), use_texture_storage_ext_(false), use_texture_format_bgra_(false), use_texture_usage_hint_(false), @@ -1250,9 +1224,7 @@ void ResourceProvider::InitializeSoftware() { DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK_NE(RESOURCE_TYPE_BITMAP, default_resource_type_); - - default_resource_type_ = RESOURCE_TYPE_BITMAP; + DCHECK_EQ(default_resource_type_, RESOURCE_TYPE_BITMAP); // Pick an arbitrary limit here similar to what hardware might. max_texture_size_ = 16 * 1024; best_texture_format_ = RGBA_8888; @@ -1260,13 +1232,11 @@ void ResourceProvider::InitializeGL() { DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_EQ(default_resource_type_, RESOURCE_TYPE_GL_TEXTURE); DCHECK(!texture_uploader_); - DCHECK_NE(RESOURCE_TYPE_GL_TEXTURE, default_resource_type_); DCHECK(!texture_id_allocator_); DCHECK(!buffer_id_allocator_); - default_resource_type_ = RESOURCE_TYPE_GL_TEXTURE; - const ContextProvider::Capabilities& caps = output_surface_->context_provider()->ContextCapabilities(); @@ -1303,6 +1273,12 @@ return child; } +void ResourceProvider::SetChildNeedsSyncPoints(int child_id, bool needs) { + ChildMap::iterator it = children_.find(child_id); + DCHECK(it != children_.end()); + it->second.needs_sync_points = needs; +} + void ResourceProvider::DestroyChild(int child_id) { ChildMap::iterator it = children_.find(child_id); DCHECK(it != children_.end()); @@ -1380,9 +1356,9 @@ ResourceIdMap::iterator resource_in_map_it = child_info.child_to_parent_map.find(it->id); if (resource_in_map_it != child_info.child_to_parent_map.end()) { - Resource& resource = resources_[resource_in_map_it->second]; - resource.marked_for_deletion = false; - resource.imported_count++; + Resource* resource = GetResource(resource_in_map_it->second); + resource->marked_for_deletion = false; + resource->imported_count++; continue; } @@ -1397,25 +1373,27 @@ } ResourceId local_id = next_id_++; - Resource& resource = resources_[local_id]; + Resource* resource = nullptr; if (it->is_software) { - resource = + resource = InsertResource( + local_id, Resource(it->mailbox_holder.mailbox, it->size, Resource::DELEGATED, - GL_LINEAR, it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE); + GL_LINEAR, it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE)); } else { - resource = Resource(0, it->size, Resource::DELEGATED, - it->mailbox_holder.texture_target, it->filter, 0, - it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE, - TEXTURE_HINT_IMMUTABLE, it->format); - resource.mailbox = TextureMailbox(it->mailbox_holder.mailbox, - it->mailbox_holder.texture_target, - it->mailbox_holder.sync_point); + resource = InsertResource( + local_id, Resource(0, it->size, Resource::DELEGATED, + it->mailbox_holder.texture_target, it->filter, 0, + it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE, + TEXTURE_HINT_IMMUTABLE, it->format)); + resource->mailbox = TextureMailbox(it->mailbox_holder.mailbox, + it->mailbox_holder.texture_target, + it->mailbox_holder.sync_point); } - resource.child_id = child; + resource->child_id = child; // Don't allocate a texture for a child. - resource.allocated = true; - resource.imported_count = 1; - resource.allow_overlay = it->allow_overlay; + resource->allocated = true; + resource->imported_count = 1; + resource->allow_overlay = it->allow_overlay; child_info.parent_to_child_map[local_id] = it->id; child_info.child_to_parent_map[it->id] = local_id; } @@ -1438,7 +1416,7 @@ DCHECK(it != child_info.child_to_parent_map.end()); ResourceId local_id = it->second; - DCHECK(!resources_[local_id].marked_for_deletion); + DCHECK(!GetResource(local_id)->marked_for_deletion); child_info.in_use_resources.insert(local_id); } @@ -1683,7 +1661,7 @@ resource.imported_count = 0; DeleteResourceInternal(it, style); } - if (need_sync_point) { + if (need_sync_point && child_info->needs_sync_points) { DCHECK(gl); GLuint sync_point = gl->InsertSyncPointCHROMIUM(); for (size_t i = 0; i < to_return.size(); ++i) {
diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h index b505f450..0bb241b 100644 --- a/cc/resources/resource_provider.h +++ b/cc/resources/resource_provider.h
@@ -74,8 +74,7 @@ TEXTURE_HINT_IMMUTABLE | TEXTURE_HINT_FRAMEBUFFER }; enum ResourceType { - RESOURCE_TYPE_INVALID = 0, - RESOURCE_TYPE_GL_TEXTURE = 1, + RESOURCE_TYPE_GL_TEXTURE, RESOURCE_TYPE_BITMAP, }; @@ -175,6 +174,10 @@ // Destroys accounting for the child, deleting all accounted resources. void DestroyChild(int child); + // Sets whether resources need sync points set on them when returned to this + // child. Defaults to true. + void SetChildNeedsSyncPoints(int child, bool needs_sync_points); + // Gets the child->parent resource ID map. const ResourceIdMap& GetChildToParentMap(int child) const; @@ -438,7 +441,6 @@ struct Resource { enum Origin { INTERNAL, EXTERNAL, DELEGATED }; - Resource(); ~Resource(); Resource(unsigned texture_id, const gfx::Size& size, @@ -518,6 +520,7 @@ ReturnCallback return_callback; ResourceIdSet in_use_resources; bool marked_for_deletion; + bool needs_sync_points; }; typedef base::hash_map<int, Child> ChildMap; @@ -531,12 +534,14 @@ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, BlockingTaskRunner* blocking_main_thread_task_runner, int highp_threshold_min, + ResourceType default_resource_type, bool use_rgba_4444_texture_format, size_t id_allocation_chunk_size); void InitializeSoftware(); void InitializeGL(); + Resource* InsertResource(ResourceId id, const Resource& resource); Resource* GetResource(ResourceId id); const Resource* LockForRead(ResourceId id); void UnlockForRead(ResourceId id); @@ -582,7 +587,7 @@ int next_child_; ChildMap children_; - ResourceType default_resource_type_; + const ResourceType default_resource_type_; bool use_texture_storage_ext_; bool use_texture_format_bgra_; bool use_texture_usage_hint_;
diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc index 72a061f7..7ebc0e3 100644 --- a/cc/resources/resource_provider_unittest.cc +++ b/cc/resources/resource_provider_unittest.cc
@@ -371,9 +371,6 @@ lock_software.sk_bitmap()->getSize()); break; } - case ResourceProvider::RESOURCE_TYPE_INVALID: - NOTREACHED(); - break; } } @@ -414,9 +411,6 @@ child_output_surface_ = FakeOutputSurface::CreateSoftware( make_scoped_ptr(new SoftwareOutputDevice)); break; - case ResourceProvider::RESOURCE_TYPE_INVALID: - NOTREACHED(); - break; } CHECK(output_surface_->BindToClient(&output_surface_client_)); CHECK(child_output_surface_->BindToClient(&child_output_surface_client_)); @@ -937,6 +931,7 @@ ReturnedResourceArray returned_to_child; int child_id = resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); + resource_provider_->SetChildNeedsSyncPoints(child_id, false); { // Transfer some resources to the parent. ResourceProvider::ResourceIdArray resource_ids_to_transfer; @@ -958,6 +953,35 @@ resource_ids_to_transfer); } + { + EXPECT_EQ(0u, returned_to_child.size()); + + // Transfer resources back from the parent to the child. Set no resources as + // being in use. + ResourceProvider::ResourceIdArray no_resources; + resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources); + + ASSERT_EQ(3u, returned_to_child.size()); + std::map<ResourceProvider::ResourceId, unsigned int> returned_sync_points; + for (const auto& returned : returned_to_child) + returned_sync_points[returned.id] = returned.sync_point; + + EXPECT_TRUE(returned_sync_points.find(id1) != returned_sync_points.end()); + // No new sync point should be created transferring back. + EXPECT_TRUE(returned_sync_points.find(id1) != returned_sync_points.end()); + EXPECT_EQ(0u, returned_sync_points[id1]); + EXPECT_TRUE(returned_sync_points.find(id2) != returned_sync_points.end()); + EXPECT_EQ(0u, returned_sync_points[id2]); + // Original sync point given should be returned. + EXPECT_TRUE(returned_sync_points.find(id3) != returned_sync_points.end()); + EXPECT_EQ(external_sync_point, returned_sync_points[id3]); + EXPECT_FALSE(returned_to_child[0].lost); + EXPECT_FALSE(returned_to_child[1].lost); + EXPECT_FALSE(returned_to_child[2].lost); + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); + returned_to_child.clear(); + } + resource_provider_->DestroyChild(child_id); }
diff --git a/cc/resources/texture_mailbox_deleter_unittest.cc b/cc/resources/texture_mailbox_deleter_unittest.cc index 05e33a3..15b42507 100644 --- a/cc/resources/texture_mailbox_deleter_unittest.cc +++ b/cc/resources/texture_mailbox_deleter_unittest.cc
@@ -4,7 +4,8 @@ #include "cc/resources/texture_mailbox_deleter.h" -#include "base/message_loop/message_loop_proxy.h" +#include "base/single_thread_task_runner.h" +#include "base/thread_task_runner_handle.h" #include "cc/resources/single_release_callback.h" #include "cc/test/test_context_provider.h" #include "cc/test/test_web_graphics_context_3d.h" @@ -15,7 +16,7 @@ TEST(TextureMailboxDeleterTest, Destroy) { scoped_ptr<TextureMailboxDeleter> deleter( - new TextureMailboxDeleter(base::MessageLoopProxy::current())); + new TextureMailboxDeleter(base::ThreadTaskRunnerHandle::Get())); scoped_refptr<TestContextProvider> context_provider = TestContextProvider::Create();
diff --git a/cc/resources/tile_manager_perftest.cc b/cc/resources/tile_manager_perftest.cc index 236f91853..0913666 100644 --- a/cc/resources/tile_manager_perftest.cc +++ b/cc/resources/tile_manager_perftest.cc
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/location.h" +#include "base/thread_task_runner_handle.h" #include "base/time/time.h" #include "cc/debug/lap_timer.h" #include "cc/resources/raster_buffer.h" @@ -88,7 +90,7 @@ : memory_limit_policy_(ALLOW_ANYTHING), max_tiles_(10000), id_(7), - proxy_(base::MessageLoopProxy::current()), + proxy_(base::ThreadTaskRunnerHandle::Get()), host_impl_(ImplSidePaintingSettings(10000), &proxy_, &shared_bitmap_manager_,
diff --git a/cc/resources/tile_manager_unittest.cc b/cc/resources/tile_manager_unittest.cc index cce307c..8b830bf 100644 --- a/cc/resources/tile_manager_unittest.cc +++ b/cc/resources/tile_manager_unittest.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/thread_task_runner_handle.h" #include "cc/resources/eviction_tile_priority_queue.h" #include "cc/resources/raster_tile_priority_queue.h" #include "cc/resources/resource_pool.h" @@ -39,7 +40,7 @@ max_tiles_(10000), ready_to_activate_(false), id_(7), - proxy_(base::MessageLoopProxy::current()), + proxy_(base::ThreadTaskRunnerHandle::Get()), host_impl_(LowResTilingsSettings(), &proxy_, &shared_bitmap_manager_,
diff --git a/cc/resources/tile_task_worker_pool_unittest.cc b/cc/resources/tile_task_worker_pool_unittest.cc index c581e97..34de309 100644 --- a/cc/resources/tile_task_worker_pool_unittest.cc +++ b/cc/resources/tile_task_worker_pool_unittest.cc
@@ -8,6 +8,9 @@ #include <vector> #include "base/cancelable_callback.h" +#include "base/location.h" +#include "base/single_thread_task_runner.h" +#include "base/thread_task_runner_handle.h" #include "cc/base/unique_notifier.h" #include "cc/resources/bitmap_tile_task_worker_pool.h" #include "cc/resources/gpu_rasterizer.h" @@ -131,7 +134,7 @@ : context_provider_(TestContextProvider::Create()), worker_context_provider_(TestContextProvider::Create()), all_tile_tasks_finished_( - base::MessageLoopProxy::current().get(), + base::ThreadTaskRunnerHandle::Get().get(), base::Bind(&TileTaskWorkerPoolTest::AllTileTasksFinished, base::Unretained(this))), timeout_seconds_(5), @@ -143,14 +146,14 @@ case TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER: Create3dOutputSurfaceAndResourceProvider(); tile_task_worker_pool_ = PixelBufferTileTaskWorkerPool::Create( - base::MessageLoopProxy::current().get(), &task_graph_runner_, + base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_, context_provider_.get(), resource_provider_.get(), kMaxTransferBufferUsageBytes); break; case TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY: Create3dOutputSurfaceAndResourceProvider(); tile_task_worker_pool_ = ZeroCopyTileTaskWorkerPool::Create( - base::MessageLoopProxy::current().get(), &task_graph_runner_, + base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_, resource_provider_.get()); break; case TILE_TASK_WORKER_POOL_TYPE_ONE_COPY: @@ -158,20 +161,20 @@ staging_resource_pool_ = ResourcePool::Create(resource_provider_.get(), GL_TEXTURE_2D); tile_task_worker_pool_ = OneCopyTileTaskWorkerPool::Create( - base::MessageLoopProxy::current().get(), &task_graph_runner_, + base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_, context_provider_.get(), resource_provider_.get(), staging_resource_pool_.get()); break; case TILE_TASK_WORKER_POOL_TYPE_GPU: Create3dOutputSurfaceAndResourceProvider(); tile_task_worker_pool_ = GpuTileTaskWorkerPool::Create( - base::MessageLoopProxy::current().get(), &task_graph_runner_, + base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_, context_provider_.get(), resource_provider_.get(), false, 0); break; case TILE_TASK_WORKER_POOL_TYPE_BITMAP: CreateSoftwareOutputSurfaceAndResourceProvider(); tile_task_worker_pool_ = BitmapTileTaskWorkerPool::Create( - base::MessageLoopProxy::current().get(), &task_graph_runner_, + base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_, resource_provider_.get()); break; } @@ -208,7 +211,7 @@ if (timeout_seconds_) { timeout_.Reset(base::Bind(&TileTaskWorkerPoolTest::OnTimeout, base::Unretained(this))); - base::MessageLoopProxy::current()->PostDelayedTask( + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, timeout_.callback(), base::TimeDelta::FromSeconds(timeout_seconds_)); }
diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc index 71fb318..d520a66 100644 --- a/cc/surfaces/display.cc +++ b/cc/surfaces/display.cc
@@ -4,7 +4,7 @@ #include "cc/surfaces/display.h" -#include "base/message_loop/message_loop.h" +#include "base/thread_task_runner_handle.h" #include "base/trace_event/trace_event.h" #include "cc/debug/benchmark_instrumentation.h" #include "cc/output/compositor_frame.h" @@ -34,9 +34,9 @@ settings_(settings), device_scale_factor_(1.f), blocking_main_thread_task_runner_( - BlockingTaskRunner::Create(base::MessageLoopProxy::current())), + BlockingTaskRunner::Create(base::ThreadTaskRunnerHandle::Get())), texture_mailbox_deleter_( - new TextureMailboxDeleter(base::MessageLoopProxy::current())) { + new TextureMailboxDeleter(base::ThreadTaskRunnerHandle::Get())) { manager_->AddObserver(this); }
diff --git a/cc/surfaces/surface_aggregator.cc b/cc/surfaces/surface_aggregator.cc index 4a7d9524f..41bb632 100644 --- a/cc/surfaces/surface_aggregator.cc +++ b/cc/surfaces/surface_aggregator.cc
@@ -120,6 +120,10 @@ if (it == surface_id_to_resource_child_id_.end()) { int child_id = provider_->CreateChild(base::Bind(&UnrefHelper, surface->factory())); + if (surface->factory()) { + provider_->SetChildNeedsSyncPoints( + child_id, surface->factory()->needs_sync_points()); + } surface_id_to_resource_child_id_[surface->surface_id()] = child_id; return child_id; } else {
diff --git a/cc/surfaces/surface_display_output_surface.cc b/cc/surfaces/surface_display_output_surface.cc index 6769e741..ece25711 100644 --- a/cc/surfaces/surface_display_output_surface.cc +++ b/cc/surfaces/surface_display_output_surface.cc
@@ -23,6 +23,7 @@ surface_manager_(surface_manager), factory_(surface_manager, this), allocator_(allocator) { + factory_.set_needs_sync_points(false); capabilities_.delegated_rendering = true; capabilities_.max_frames_pending = 1; capabilities_.adjust_deadline_for_parent = true;
diff --git a/cc/surfaces/surface_factory.cc b/cc/surfaces/surface_factory.cc index aead4f68..9bb50ac 100644 --- a/cc/surfaces/surface_factory.cc +++ b/cc/surfaces/surface_factory.cc
@@ -13,7 +13,10 @@ namespace cc { SurfaceFactory::SurfaceFactory(SurfaceManager* manager, SurfaceFactoryClient* client) - : manager_(manager), client_(client), holder_(client) { + : manager_(manager), + client_(client), + holder_(client), + needs_sync_points_(true) { } SurfaceFactory::~SurfaceFactory() {
diff --git a/cc/surfaces/surface_factory.h b/cc/surfaces/surface_factory.h index b6b627fb..c83fa32 100644 --- a/cc/surfaces/surface_factory.h +++ b/cc/surfaces/surface_factory.h
@@ -63,11 +63,19 @@ SurfaceManager* manager() { return manager_; } + // This can be set to false if resources from this SurfaceFactory don't need + // to have sync points set on them when returned from the Display, for + // example if the Display shares a context with the creator. + bool needs_sync_points() const { return needs_sync_points_; } + void set_needs_sync_points(bool needs) { needs_sync_points_ = needs; } + private: SurfaceManager* manager_; SurfaceFactoryClient* client_; SurfaceResourceHolder holder_; + bool needs_sync_points_; + typedef base::ScopedPtrHashMap<SurfaceId, Surface> OwningSurfaceMap; base::ScopedPtrHashMap<SurfaceId, Surface> surface_map_;
diff --git a/cc/test/fake_external_begin_frame_source.cc b/cc/test/fake_external_begin_frame_source.cc index c1885c14..3c35536 100644 --- a/cc/test/fake_external_begin_frame_source.cc +++ b/cc/test/fake_external_begin_frame_source.cc
@@ -5,7 +5,8 @@ #include "cc/test/fake_external_begin_frame_source.h" #include "base/location.h" -#include "base/message_loop/message_loop.h" +#include "base/single_thread_task_runner.h" +#include "base/thread_task_runner_handle.h" #include "base/time/time.h" #include "cc/test/begin_frame_args_test.h" @@ -45,7 +46,7 @@ } void FakeExternalBeginFrameSource::PostTestOnBeginFrame() { - base::MessageLoop::current()->PostDelayedTask( + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, base::Bind(&FakeExternalBeginFrameSource::TestOnBeginFrame, weak_ptr_factory_.GetWeakPtr()), base::TimeDelta::FromMilliseconds(milliseconds_per_frame_));
diff --git a/cc/test/fake_impl_proxy.h b/cc/test/fake_impl_proxy.h index 69eb5d21..6cbf9a3 100644 --- a/cc/test/fake_impl_proxy.h +++ b/cc/test/fake_impl_proxy.h
@@ -5,20 +5,25 @@ #ifndef CC_TEST_FAKE_IMPL_PROXY_H_ #define CC_TEST_FAKE_IMPL_PROXY_H_ +#include "base/thread_task_runner_handle.h" #include "cc/test/fake_proxy.h" #include "cc/trees/single_thread_proxy.h" +namespace base { +class SingleThreadIdleTaskRunner; +} + namespace cc { class FakeImplProxy : public FakeProxy { public: FakeImplProxy() - : FakeProxy(base::MessageLoopProxy::current(), nullptr), + : FakeProxy(base::ThreadTaskRunnerHandle::Get(), nullptr), set_impl_thread_(this) {} explicit FakeImplProxy( scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) - : FakeProxy(base::MessageLoopProxy::current(), impl_task_runner), + : FakeProxy(base::ThreadTaskRunnerHandle::Get(), impl_task_runner), set_impl_thread_(this) {} private:
diff --git a/cc/test/fake_tile_manager.cc b/cc/test/fake_tile_manager.cc index d33093f..47634eea 100644 --- a/cc/test/fake_tile_manager.cc +++ b/cc/test/fake_tile_manager.cc
@@ -8,6 +8,7 @@ #include <limits> #include "base/lazy_instance.h" +#include "base/thread_task_runner_handle.h" #include "cc/resources/raster_buffer.h" #include "cc/resources/tile_task_runner.h" @@ -65,7 +66,7 @@ FakeTileManager::FakeTileManager(TileManagerClient* client) : TileManager(client, - base::MessageLoopProxy::current(), + base::ThreadTaskRunnerHandle::Get(), nullptr, g_fake_tile_task_runner.Pointer(), std::numeric_limits<size_t>::max()) { @@ -74,7 +75,7 @@ FakeTileManager::FakeTileManager(TileManagerClient* client, ResourcePool* resource_pool) : TileManager(client, - base::MessageLoopProxy::current(), + base::ThreadTaskRunnerHandle::Get(), resource_pool, g_fake_tile_task_runner.Pointer(), std::numeric_limits<size_t>::max()) {
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc index a39c452..93ddf12 100644 --- a/cc/test/layer_tree_test.cc +++ b/cc/test/layer_tree_test.cc
@@ -5,6 +5,9 @@ #include "cc/test/layer_tree_test.h" #include "base/command_line.h" +#include "base/location.h" +#include "base/single_thread_task_runner.h" +#include "base/thread_task_runner_handle.h" #include "cc/animation/animation.h" #include "cc/animation/animation_registrar.h" #include "cc/animation/layer_animation_controller.h" @@ -663,12 +666,12 @@ external_begin_frame_source_ = external_begin_frame_source.get(); } - DCHECK(!impl_thread_ || impl_thread_->message_loop_proxy().get()); + DCHECK(!impl_thread_ || impl_thread_->task_runner().get()); layer_tree_host_ = LayerTreeHostForTesting::Create( this, client_.get(), shared_bitmap_manager_.get(), gpu_memory_buffer_manager_.get(), task_graph_runner_.get(), settings_, - base::MessageLoopProxy::current(), - impl_thread_ ? impl_thread_->message_loop_proxy() : NULL, + base::ThreadTaskRunnerHandle::Get(), + impl_thread_ ? impl_thread_->task_runner() : NULL, external_begin_frame_source.Pass()); ASSERT_TRUE(layer_tree_host_); @@ -792,7 +795,7 @@ ASSERT_TRUE(impl_thread_->Start()); } - main_task_runner_ = base::MessageLoopProxy::current(); + main_task_runner_ = base::ThreadTaskRunnerHandle::Get(); shared_bitmap_manager_.reset(new TestSharedBitmapManager); gpu_memory_buffer_manager_.reset(new TestGpuMemoryBufferManager);
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc index c2dc5b5..2c3fb653 100644 --- a/cc/test/pixel_test.cc +++ b/cc/test/pixel_test.cc
@@ -5,9 +5,9 @@ #include "cc/test/pixel_test.h" #include "base/command_line.h" -#include "base/message_loop/message_loop_proxy.h" #include "base/path_service.h" #include "base/run_loop.h" +#include "base/thread_task_runner_handle.h" #include "cc/base/switches.h" #include "cc/output/compositor_frame_metadata.h" #include "cc/output/copy_output_request.h" @@ -37,7 +37,7 @@ disable_picture_quad_image_filtering_(false), output_surface_client_(new FakeOutputSurfaceClient), main_thread_task_runner_( - BlockingTaskRunner::Create(base::MessageLoopProxy::current())) { + BlockingTaskRunner::Create(base::ThreadTaskRunnerHandle::Get())) { } PixelTest::~PixelTest() {} @@ -143,7 +143,7 @@ 1); texture_mailbox_deleter_ = make_scoped_ptr( - new TextureMailboxDeleter(base::MessageLoopProxy::current())); + new TextureMailboxDeleter(base::ThreadTaskRunnerHandle::Get())); renderer_ = GLRenderer::Create( this, &settings_.renderer_settings, output_surface_.get(),
diff --git a/cc/test/test_context_support.cc b/cc/test/test_context_support.cc index f74f692..b3c45563 100644 --- a/cc/test/test_context_support.cc +++ b/cc/test/test_context_support.cc
@@ -5,7 +5,9 @@ #include "cc/test/test_context_support.h" #include "base/bind.h" -#include "base/message_loop/message_loop.h" +#include "base/location.h" +#include "base/single_thread_task_runner.h" +#include "base/thread_task_runner_handle.h" namespace cc { @@ -18,19 +20,17 @@ void TestContextSupport::SignalSyncPoint(uint32 sync_point, const base::Closure& callback) { sync_point_callbacks_.push_back(callback); - base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&TestContextSupport::CallAllSyncPointCallbacks, - weak_ptr_factory_.GetWeakPtr())); + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&TestContextSupport::CallAllSyncPointCallbacks, + weak_ptr_factory_.GetWeakPtr())); } void TestContextSupport::SignalQuery(uint32 query, const base::Closure& callback) { sync_point_callbacks_.push_back(callback); - base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&TestContextSupport::CallAllSyncPointCallbacks, - weak_ptr_factory_.GetWeakPtr())); + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&TestContextSupport::CallAllSyncPointCallbacks, + weak_ptr_factory_.GetWeakPtr())); } void TestContextSupport::SetSurfaceVisible(bool visible) { @@ -41,8 +41,8 @@ void TestContextSupport::CallAllSyncPointCallbacks() { for (size_t i = 0; i < sync_point_callbacks_.size(); ++i) { - base::MessageLoop::current()->PostTask( - FROM_HERE, sync_point_callbacks_[i]); + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + sync_point_callbacks_[i]); } sync_point_callbacks_.clear(); }
diff --git a/cc/trees/blocking_task_runner_unittest.cc b/cc/trees/blocking_task_runner_unittest.cc index ba4f96a8..f837a7cc 100644 --- a/cc/trees/blocking_task_runner_unittest.cc +++ b/cc/trees/blocking_task_runner_unittest.cc
@@ -5,7 +5,10 @@ #include "cc/trees/blocking_task_runner.h" #include "base/bind.h" +#include "base/location.h" #include "base/run_loop.h" +#include "base/single_thread_task_runner.h" +#include "base/thread_task_runner_handle.h" #include "cc/test/ordered_simple_task_runner.h" #include "testing/gtest/include/gtest/gtest.h" @@ -19,7 +22,7 @@ TEST(BlockingTaskRunnerTest, NoCapture) { bool did_run = false; scoped_ptr<BlockingTaskRunner> runner( - BlockingTaskRunner::Create(base::MessageLoopProxy::current())); + BlockingTaskRunner::Create(base::ThreadTaskRunnerHandle::Get())); runner->PostTask(FROM_HERE, base::Bind(&TestTask, &did_run)); EXPECT_FALSE(did_run); base::RunLoop().RunUntilIdle(); @@ -29,7 +32,7 @@ TEST(BlockingTaskRunnerTest, Capture) { bool did_run = false; scoped_ptr<BlockingTaskRunner> runner( - BlockingTaskRunner::Create(base::MessageLoopProxy::current())); + BlockingTaskRunner::Create(base::ThreadTaskRunnerHandle::Get())); { BlockingTaskRunner::CapturePostTasks capture(runner.get()); runner->PostTask(FROM_HERE, base::Bind(&TestTask, &did_run));
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc index b4a268f..0e25f06 100644 --- a/cc/trees/draw_property_utils.cc +++ b/cc/trees/draw_property_utils.cc
@@ -267,14 +267,34 @@ gfx::Transform clip_to_target; gfx::Transform target_to_clip; - bool success = - transform_tree.ComputeTransform(parent_transform_node->id, - clip_node->data.target_id, - &parent_to_target) && - transform_tree.ComputeTransform( - transform_node->id, clip_node->data.target_id, &clip_to_target) && - transform_tree.ComputeTransform(clip_node->data.target_id, - transform_node->id, &target_to_clip); + const bool target_is_root_surface = clip_node->data.target_id == 1; + // When the target is the root surface, we need to include the root + // transform by walking up to the root of the transform tree. + const int target_id = + target_is_root_surface ? 0 : clip_node->data.target_id; + + bool success = true; + if (parent_transform_node->data.content_target_id == + clip_node->data.target_id) { + parent_to_target = parent_transform_node->data.to_target; + } else { + success &= transform_tree.ComputeTransformWithDestinationSublayerScale( + parent_transform_node->id, target_id, &parent_to_target); + } + + if (transform_node->data.content_target_id == clip_node->data.target_id) { + clip_to_target = transform_node->data.to_target; + } else { + success &= transform_tree.ComputeTransformWithDestinationSublayerScale( + transform_node->id, target_id, &clip_to_target); + } + + if (transform_node->data.content_target_id == clip_node->data.target_id && + transform_node->data.ancestors_are_invertible) { + target_to_clip = transform_node->data.from_target; + } else { + success &= clip_to_target.GetInverse(&target_to_clip); + } // If we can't compute a transform, it's because we had to use the inverse // of a singular transform. We won't draw in this case, so there's no need
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc index 53bfcb8f..ac473ab 100644 --- a/cc/trees/layer_tree_host.cc +++ b/cc/trees/layer_tree_host.cc
@@ -11,10 +11,12 @@ #include "base/atomic_sequence_num.h" #include "base/bind.h" #include "base/command_line.h" -#include "base/message_loop/message_loop.h" +#include "base/location.h" #include "base/metrics/histogram.h" +#include "base/single_thread_task_runner.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" +#include "base/thread_task_runner_handle.h" #include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event_argument.h" #include "cc/animation/animation_registrar.h" @@ -823,7 +825,7 @@ base::Unretained(this))); static base::TimeDelta prepaint_delay = base::TimeDelta::FromMilliseconds(100); - base::MessageLoop::current()->PostDelayedTask( + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, prepaint_callback_.callback(), prepaint_delay); }
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index fa0bfc34..fcb041e 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -11,6 +11,8 @@ #include "base/command_line.h" #include "base/containers/hash_tables.h" #include "base/containers/scoped_ptr_hash_map.h" +#include "base/location.h" +#include "base/thread_task_runner_handle.h" #include "cc/animation/scrollbar_animation_controller_thinning.h" #include "cc/base/math_util.h" #include "cc/input/page_scale_animation.h" @@ -81,8 +83,8 @@ public LayerTreeHostImplClient { public: LayerTreeHostImplTest() - : proxy_(base::MessageLoopProxy::current(), - base::MessageLoopProxy::current()), + : proxy_(base::ThreadTaskRunnerHandle::Get(), + base::ThreadTaskRunnerHandle::Get()), always_impl_thread_(&proxy_), always_main_thread_blocked_(&proxy_), shared_bitmap_manager_(new TestSharedBitmapManager),
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc index ef70f825..51994c7 100644 --- a/cc/trees/layer_tree_host_unittest.cc +++ b/cc/trees/layer_tree_host_unittest.cc
@@ -7,7 +7,10 @@ #include <algorithm> #include "base/auto_reset.h" +#include "base/location.h" +#include "base/single_thread_task_runner.h" #include "base/synchronization/lock.h" +#include "base/thread_task_runner_handle.h" #include "cc/animation/timing_function.h" #include "cc/debug/frame_rate_counter.h" #include "cc/layers/content_layer.h" @@ -2368,7 +2371,7 @@ new TestSharedBitmapManager()); scoped_ptr<LayerTreeHost> host = LayerTreeHost::CreateSingleThreaded( &client, &client, shared_bitmap_manager.get(), NULL, NULL, settings, - base::MessageLoopProxy::current(), nullptr); + base::ThreadTaskRunnerHandle::Get(), nullptr); client.SetLayerTreeHost(host.get()); host->Composite(base::TimeTicks::Now()); @@ -2387,7 +2390,7 @@ new TestSharedBitmapManager()); scoped_ptr<LayerTreeHost> host = LayerTreeHost::CreateSingleThreaded( &client, &client, shared_bitmap_manager.get(), NULL, NULL, settings, - base::MessageLoopProxy::current(), nullptr); + base::ThreadTaskRunnerHandle::Get(), nullptr); client.SetLayerTreeHost(host.get()); host->Composite(base::TimeTicks::Now()); @@ -2406,7 +2409,7 @@ new TestSharedBitmapManager()); scoped_ptr<LayerTreeHost> host = LayerTreeHost::CreateSingleThreaded( &client, &client, shared_bitmap_manager.get(), NULL, NULL, settings, - base::MessageLoopProxy::current(), nullptr); + base::ThreadTaskRunnerHandle::Get(), nullptr); client.SetLayerTreeHost(host.get()); host->Composite(base::TimeTicks::Now()); @@ -2426,7 +2429,7 @@ new TestSharedBitmapManager()); scoped_ptr<LayerTreeHost> host = LayerTreeHost::CreateSingleThreaded( &client, &client, shared_bitmap_manager.get(), NULL, NULL, settings, - base::MessageLoopProxy::current(), nullptr); + base::ThreadTaskRunnerHandle::Get(), nullptr); client.SetLayerTreeHost(host.get()); host->Composite(base::TimeTicks::Now());
diff --git a/cc/trees/layer_tree_host_unittest_no_message_loop.cc b/cc/trees/layer_tree_host_unittest_no_message_loop.cc index 3abc4dc8..0b68ffb2 100644 --- a/cc/trees/layer_tree_host_unittest_no_message_loop.cc +++ b/cc/trees/layer_tree_host_unittest_no_message_loop.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/message_loop/message_loop_proxy.h" +#include "base/thread_task_runner_handle.h" #include "base/threading/simple_thread.h" #include "cc/layers/delegated_frame_provider.h" #include "cc/layers/delegated_frame_resource_collection.h" @@ -92,9 +92,9 @@ // base::DelegateSimpleThread::Delegate override. void Run() override { - ASSERT_FALSE(base::MessageLoopProxy::current().get()); + ASSERT_FALSE(base::ThreadTaskRunnerHandle::IsSet()); RunTestWithoutMessageLoop(); - EXPECT_FALSE(base::MessageLoopProxy::current().get()); + EXPECT_FALSE(base::ThreadTaskRunnerHandle::IsSet()); } protected:
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc index be972e9..46cc3e6 100644 --- a/cc/trees/layer_tree_host_unittest_scroll.cc +++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -4,7 +4,10 @@ #include "cc/trees/layer_tree_host.h" +#include "base/location.h" #include "base/memory/weak_ptr.h" +#include "base/single_thread_task_runner.h" +#include "base/thread_task_runner_handle.h" #include "cc/layers/layer.h" #include "cc/layers/layer_impl.h" #include "cc/layers/picture_layer.h" @@ -1120,20 +1123,18 @@ LayerTreeSettings settings; ThreadCheckingInputHandlerClient input_handler_client( - impl_thread.message_loop_proxy().get(), &received_stop_flinging); + impl_thread.task_runner().get(), &received_stop_flinging); FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D); - ASSERT_TRUE(impl_thread.message_loop_proxy().get()); + ASSERT_TRUE(impl_thread.task_runner().get()); scoped_ptr<SharedBitmapManager> shared_bitmap_manager( new TestSharedBitmapManager()); scoped_ptr<LayerTreeHost> layer_tree_host = LayerTreeHost::CreateThreaded( &client, shared_bitmap_manager.get(), NULL, NULL, settings, - base::MessageLoopProxy::current(), impl_thread.message_loop_proxy(), - nullptr); + base::ThreadTaskRunnerHandle::Get(), impl_thread.task_runner(), nullptr); - impl_thread.message_loop_proxy() - ->PostTask(FROM_HERE, - base::Bind(&BindInputHandlerOnCompositorThread, + impl_thread.task_runner()->PostTask( + FROM_HERE, base::Bind(&BindInputHandlerOnCompositorThread, layer_tree_host->GetInputHandler(), base::Unretained(&input_handler_client)));
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc index d013b12..0149befe 100644 --- a/cc/trees/property_tree_builder.cc +++ b/cc/trees/property_tree_builder.cc
@@ -33,6 +33,7 @@ float device_scale_factor; bool in_subtree_of_page_scale_application_layer; bool should_flatten; + bool ancestor_clips_subtree; const gfx::Transform* device_transform; gfx::Vector2dF scroll_compensation_adjustment; }; @@ -52,9 +53,10 @@ static bool RequiresClipNode(Layer* layer, const DataForRecursion& data, - int parent_transform_id) { + int parent_transform_id, + bool is_clipped) { const bool render_surface_applies_clip = - layer->render_surface() && layer->is_clipped(); + layer->render_surface() && is_clipped; const bool render_surface_may_grow_due_to_clip_children = layer->render_surface() && layer->num_unclipped_descendants() > 0; @@ -72,6 +74,10 @@ return !axis_aligned_with_respect_to_parent; } +static bool LayerClipsSubtree(Layer* layer) { + return layer->masks_to_bounds() || layer->mask_layer(); +} + void AddClipNodeIfNeeded(const DataForRecursion& data_from_ancestor, Layer* layer, bool created_transform_node, @@ -79,17 +85,29 @@ ClipNode* parent = GetClipParent(data_from_ancestor, layer); int parent_id = parent->id; - // TODO(vollick): once Andrew refactors the surface determinations out of - // CDP, the the layer->render_surface() check will be invalid. - const bool has_unclipped_surface = - layer->render_surface() && - !layer->render_surface()->is_clipped() && - layer->num_unclipped_descendants() == 0; + bool ancestor_clips_subtree = + data_from_ancestor.ancestor_clips_subtree || layer->clip_parent(); + + data_for_children->ancestor_clips_subtree = false; + bool has_unclipped_surface = false; + + if (layer->has_render_surface()) { + if (ancestor_clips_subtree && layer->num_unclipped_descendants() > 0) + data_for_children->ancestor_clips_subtree = true; + else if (!ancestor_clips_subtree && !layer->num_unclipped_descendants()) + has_unclipped_surface = true; + } else { + data_for_children->ancestor_clips_subtree = ancestor_clips_subtree; + } + + if (LayerClipsSubtree(layer)) + data_for_children->ancestor_clips_subtree = true; if (has_unclipped_surface) parent_id = 0; - if (!RequiresClipNode(layer, data_from_ancestor, parent->data.transform_id)) { + if (!RequiresClipNode(layer, data_from_ancestor, parent->data.transform_id, + data_for_children->ancestor_clips_subtree)) { // Unclipped surfaces reset the clip rect. data_for_children->clip_tree_parent = parent_id; } else if (layer->parent()) { @@ -339,6 +357,7 @@ data_for_recursion.device_scale_factor = device_scale_factor; data_for_recursion.in_subtree_of_page_scale_application_layer = false; data_for_recursion.should_flatten = false; + data_for_recursion.ancestor_clips_subtree = true; data_for_recursion.device_transform = &device_transform; ClipNode root_clip;
diff --git a/chrome/android/java/src/org/chromium/chrome/ChromeSwitches.java b/chrome/android/java/src/org/chromium/chrome/ChromeSwitches.java index da0cc9f..7cc1286 100644 --- a/chrome/android/java/src/org/chromium/chrome/ChromeSwitches.java +++ b/chrome/android/java/src/org/chromium/chrome/ChromeSwitches.java
@@ -32,12 +32,6 @@ /** Whether instant is disabled. */ public static final String DISABLE_INSTANT = "disable-instant"; - /** Whether force-enable the "hardware acceleration" preference. */ - public static final String HARDWARE_ACCELERATION = "hardware-acceleration"; - - /** If specified, enables notification center verbose logging. */ - public static final String NOTIFICATION_CENTER_LOGGING = "notification-center-logging"; - /** Enables StrictMode violation detection. By default this logs violations to logcat. */ public static final String STRICT_MODE = "strict-mode"; @@ -50,18 +44,12 @@ /** Force the crash dump to be uploaded regardless of preferences. */ public static final String FORCE_CRASH_DUMP_UPLOAD = "force-dump-upload"; - /** Do not use OAuth2 tokens for communication with Cloud Print service for Chrome to Mobile. */ - public static final String DISABLE_CHROME_TO_MOBILE_OAUTH2 = "disable-chrome-to-mobile-oauth2"; - /** Enable debug logs for the video casting feature. */ public static final String ENABLE_CAST_DEBUG_LOGS = "enable-cast-debug"; /** Prevent automatic reconnection to current Cast video when Chrome restarts. */ public static final String DISABLE_CAST_RECONNECTION = "disable-cast-reconnection"; - /** Whether site/user triggered persistent fullscreen is supported. */ - public static final String DISABLE_PERSISTENT_FULLSCREEN = "disable-persistent-fullscreen"; - /** Whether or not to enable the experimental tablet tab stack. */ public static final String ENABLE_TABLET_TAB_STACK = "enable-tablet-tab-stack"; @@ -122,9 +110,6 @@ public static final String EXPERIMENTAL_WEB_PLAFTORM_FEATURES = "enable-experimental-web-platform-features"; - /** Enable the Reader Mode icon in toolbar. */ - public static final String ENABLE_READER_MODE_TOOLBAR_ICON = "enable-reader-mode-toolbar-icon"; - /** Enable Reader Mode button animation. */ public static final String ENABLE_READER_MODE_BUTTON_ANIMATION = "enable-dom-distiller-button-animation";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBrowserProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBrowserProvider.java index 30cfae2..1e0ff7c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBrowserProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBrowserProvider.java
@@ -31,9 +31,9 @@ import android.util.LongSparseArray; import org.chromium.base.CalledByNative; -import org.chromium.base.CalledByNativeUnchecked; import org.chromium.base.ThreadUtils; import org.chromium.base.VisibleForTesting; +import org.chromium.base.annotations.CalledByNativeUnchecked; import org.chromium.base.annotations.SuppressFBWarnings; import org.chromium.chrome.browser.database.SQLiteCursor; import org.chromium.sync.AndroidSyncSettings;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/OffTheRecordDocumentTabModel.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/OffTheRecordDocumentTabModel.java index 5c6fde54..e945c7d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/OffTheRecordDocumentTabModel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/OffTheRecordDocumentTabModel.java
@@ -143,7 +143,7 @@ @Override public boolean setLastShownId(int id) { - ensureTabModelImpl(); + if (!isDocumentTabModelImplCreated()) return false; return getDelegateDocumentTabModel().setLastShownId(id); }
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd index a7218b7..d76ee63 100644 --- a/chrome/app/chromium_strings.grd +++ b/chrome/app/chromium_strings.grd
@@ -672,6 +672,9 @@ Your changes will take effect the next time you restart your device. </message> </if> + <message name="IDS_FLAGS_DEBUG_SHORTCUTS_DESCRIPTION" desc="Description of the 'Debugging keyboard shortcuts' lab."> + Enables additional keyboard shortcuts that are useful for debugging Chromium. + </message> <!-- Obsolete System info bar --> <message name="IDS_SYSTEM_OBSOLETE_MESSAGE" desc="Message shown when your OS is no longer supported. This message is followed by a 'Learn more' link."> @@ -766,6 +769,11 @@ </message> </if> + <!-- settings reset bubble messages --> + <message name="IDS_REPORT_BUBBLE_TEXT" desc="Text for the settings reset bubble reporting checkbox."> + Help make Chromium better by reporting the current settings + </message> + <!-- chrome://settings/extensions page --> <message name="IDS_EXTENSIONS_INCOGNITO_WARNING" desc="Warns the user that Chromium cannot prevent extensions from recording history in incognito mode. Displayed in extensions management UI after an extension is selected to be run in incognito mode."> <ph name="BEGIN_BOLD"><b></ph>Warning:<ph name="END_BOLD"></b></ph> Chromium cannot prevent extensions from recording your browsing history. To disable this extension in incognito mode, unselect this option.
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 68fdfeba..c2a6190 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -5713,9 +5713,6 @@ <message name="IDS_FLAGS_DEBUG_SHORTCUTS_NAME" desc="Name of the 'Debugging keyboard shortcuts' lab."> Debugging keyboard shortcuts </message> - <message name="IDS_FLAGS_DEBUG_SHORTCUTS_DESCRIPTION" desc="Description of the 'Debugging keyboard shortcuts' lab."> - Enables additional keyboard shortcuts that are useful for debugging Chromium. - </message> <message name="IDS_FLAGS_IGNORE_GPU_BLACKLIST_NAME" desc="Name of the 'Ignore GPU blacklist' lab."> Override software rendering list </message> @@ -8456,9 +8453,6 @@ <message name="IDS_RESET_BUBBLE_TEXT" desc="Text for the settings reset bubble view full description."> <ph name="IDS_SHORT_PRODUCT_NAME">$1<ex>Chrome</ex></ph> detected that your browser settings may have been changed without your knowledge. Would you like to reset them to their original defaults? </message> - <message name="IDS_REPORT_BUBBLE_TEXT" desc="Text for the settings reset bubble reporting checkbox."> - Help make Google Chrome better by reporting the current settings - </message> <!-- SRT bubble messages --> <message name="IDS_SRT_BUBBLE_DOWNLOAD_BUTTON_TEXT" desc="Download button of the software removal tool bubble">
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd index d76eac9..5168791f 100644 --- a/chrome/app/google_chrome_strings.grd +++ b/chrome/app/google_chrome_strings.grd
@@ -595,6 +595,9 @@ Your changes will take effect the next time you restart your device. </message> </if> + <message name="IDS_FLAGS_DEBUG_SHORTCUTS_DESCRIPTION" desc="Description of the 'Debugging keyboard shortcuts' lab."> + Enables additional keyboard shortcuts that are useful for debugging Google Chrome. + </message> <!-- Obsolete System info bar --> <message name="IDS_SYSTEM_OBSOLETE_MESSAGE" desc="Message shown when your OS is no longer supported. This message is followed by a 'Learn more' link."> @@ -689,6 +692,11 @@ </message> </if> + <!-- settings reset bubble messages --> + <message name="IDS_REPORT_BUBBLE_TEXT" desc="Text for the settings reset bubble reporting checkbox."> + Help make Google Chrome better by reporting the current settings + </message> + <!-- chrome://settings/extensions page --> <message name="IDS_EXTENSIONS_INCOGNITO_WARNING" desc="Warns the user that Chrome cannot prevent extensions from recording history in incognito mode. Displayed in extensions management UI after an extension is selected to be run in incognito mode."> <ph name="BEGIN_BOLD"><b></ph>Warning:<ph name="END_BOLD"></b></ph> Google Chrome cannot prevent extensions from recording your browsing history. To disable this extension in incognito mode, unselect this option.
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index a60cd0d..da337aae 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -73,4 +73,9 @@ <message name="IDS_SETTINGS_DOWNLOADS_PROMPT_FOR_DOWNLOAD_LABEL" desc="Label for the checkbox which enables a prompt for the user to choose a download location for each download instead of using the default."> Ask where to save each file before downloading </message> + + <!-- Internet Page --> + <message name="IDS_SETTINGS_INTERNET_PAGE_TITLE" desc="Name of the settings page which displays internet preferences."> + Internet Connection + </message> </grit-part>
diff --git a/chrome/browser/PRESUBMIT.py b/chrome/browser/PRESUBMIT.py index 5b42758..72303241 100644 --- a/chrome/browser/PRESUBMIT.py +++ b/chrome/browser/PRESUBMIT.py
@@ -4,7 +4,7 @@ """Presubmit script for Chromium browser code. -This script currently only checks HTML/CSS/JS files in resources/. +This script currently checks HTML/CSS/JS files in resources/ and ui/webui/. See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts for more details about the presubmit API built into depot_tools, and see
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 949db24..48d8576 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -21,7 +21,9 @@ #include "chrome/browser/flags_storage.h" #include "chrome/common/chrome_content_client.h" #include "chrome/common/chrome_switches.h" +#include "chrome/grit/chromium_strings.h" #include "chrome/grit/generated_resources.h" +#include "chrome/grit/google_chrome_strings.h" #include "components/autofill/core/common/autofill_switches.h" #include "components/cloud_devices/common/cloud_devices_switches.h" #include "components/metrics/metrics_hashes.h" @@ -1939,7 +1941,7 @@ "answers-in-suggest", IDS_FLAGS_ENABLE_ANSWERS_IN_SUGGEST_NAME, IDS_FLAGS_ENABLE_ANSWERS_IN_SUGGEST_DESCRIPTION, - kOsAndroid | kOsWin | kOsLinux | kOsCrOS, + kOsAndroid | kOsDesktop, ENABLE_DISABLE_VALUE_TYPE(switches::kEnableAnswersInSuggest, switches::kDisableAnswersInSuggest) },
diff --git a/chrome/browser/after_startup_task_utils.cc b/chrome/browser/after_startup_task_utils.cc new file mode 100644 index 0000000..a4dc5ef --- /dev/null +++ b/chrome/browser/after_startup_task_utils.cc
@@ -0,0 +1,223 @@ +// 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/after_startup_task_utils.h" + +#include "base/lazy_instance.h" +#include "base/memory/scoped_ptr.h" +#include "base/metrics/histogram_macros.h" +#include "base/process/process_info.h" +#include "base/rand_util.h" +#include "base/synchronization/cancellation_flag.h" +#include "base/task_runner.h" +#include "base/tracked_objects.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_iterator.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" + +using content::BrowserThread; +using content::WebContents; +using content::WebContentsObserver; +using StartupCompleteFlag = base::CancellationFlag; + +namespace { + +struct AfterStartupTask { + AfterStartupTask(const tracked_objects::Location& from_here, + const scoped_refptr<base::TaskRunner>& task_runner, + const base::Closure& task) + : from_here(from_here), task_runner(task_runner), task(task) {} + ~AfterStartupTask() {} + + const tracked_objects::Location from_here; + const scoped_refptr<base::TaskRunner> task_runner; + const base::Closure task; +}; + +// The flag may be read on any thread, but must only be set on the UI thread. +base::LazyInstance<StartupCompleteFlag>::Leaky g_startup_complete_flag; + +// The queue may only be accessed on the UI thread. +base::LazyInstance<std::deque<AfterStartupTask*>>::Leaky g_after_startup_tasks; + +bool IsBrowserStartupComplete() { + // Be sure to initialize the LazyInstance on the main thread since the flag + // may only be set on it's initializing thread. + if (g_startup_complete_flag == nullptr) + return false; + return g_startup_complete_flag.Get().IsSet(); +} + +void RunTask(scoped_ptr<AfterStartupTask> queued_task) { + // We're careful to delete the caller's |task| on the target runner's thread. + DCHECK(queued_task->task_runner->RunsTasksOnCurrentThread()); + queued_task->task.Run(); +} + +void ScheduleTask(scoped_ptr<AfterStartupTask> queued_task) { + // Spread their execution over a brief time. + const int kMinDelaySec = 0; + const int kMaxDelaySec = 10; + scoped_refptr<base::TaskRunner> target_runner = queued_task->task_runner; + tracked_objects::Location from_here = queued_task->from_here; + target_runner->PostDelayedTask( + from_here, base::Bind(&RunTask, base::Passed(queued_task.Pass())), + base::TimeDelta::FromSeconds(base::RandInt(kMinDelaySec, kMaxDelaySec))); +} + +void QueueTask(scoped_ptr<AfterStartupTask> queued_task) { + if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(QueueTask, base::Passed(queued_task.Pass()))); + return; + } + + // The flag may have been set while the task to invoke this method + // on the UI thread was inflight. + if (IsBrowserStartupComplete()) { + ScheduleTask(queued_task.Pass()); + return; + } + g_after_startup_tasks.Get().push_back(queued_task.release()); +} + +void SetBrowserStartupIsComplete() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); +#if defined(OS_MACOSX) || defined(OS_WIN) || defined(OS_LINUX) + // CurrentProcessInfo::CreationTime() is not available on all platforms. + const base::Time process_creation_time = + base::CurrentProcessInfo::CreationTime(); + if (!process_creation_time.is_null()) { + UMA_HISTOGRAM_LONG_TIMES("Startup.AfterStartupTaskDelayedUntilTime", + base::Time::Now() - process_creation_time); + } +#endif // defined(OS_MACOSX) || defined(OS_WIN) || defined(OS_LINUX) + UMA_HISTOGRAM_COUNTS_10000("Startup.AfterStartupTaskCount", + g_after_startup_tasks.Get().size()); + g_startup_complete_flag.Get().Set(); + for (AfterStartupTask* queued_task : g_after_startup_tasks.Get()) + ScheduleTask(make_scoped_ptr(queued_task)); + g_after_startup_tasks.Get().clear(); + + // The shrink_to_fit() method is not available for all of our build targets. + std::deque<AfterStartupTask*>(g_after_startup_tasks.Get()) + .swap(g_after_startup_tasks.Get()); +} + +// Observes the first visible page load and sets the startup complete +// flag accordingly. +class StartupObserver : public WebContentsObserver, public base::NonThreadSafe { + public: + StartupObserver() : weak_factory_(this) {} + ~StartupObserver() override { DCHECK(IsBrowserStartupComplete()); } + + void Start(); + + private: + void OnStartupComplete() { + DCHECK(CalledOnValidThread()); + SetBrowserStartupIsComplete(); + delete this; + } + + void OnFailsafeTimeout() { OnStartupComplete(); } + + // WebContentsObserver overrides + void DidFinishLoad(content::RenderFrameHost* render_frame_host, + const GURL& validated_url) override { + if (!render_frame_host->GetParent()) + OnStartupComplete(); + } + + void DidFailLoad(content::RenderFrameHost* render_frame_host, + const GURL& validated_url, + int error_code, + const base::string16& error_description) override { + if (!render_frame_host->GetParent()) + OnStartupComplete(); + } + + void WebContentsDestroyed() override { OnStartupComplete(); } + + base::WeakPtrFactory<StartupObserver> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(StartupObserver); +}; + +void StartupObserver::Start() { + // Signal completion quickly when there is no first page to load. + const int kShortDelaySecs = 3; + base::TimeDelta delay = base::TimeDelta::FromSeconds(kShortDelaySecs); + +#if !defined(OS_ANDROID) + WebContents* contents = nullptr; + for (chrome::BrowserIterator iter; !iter.done(); iter.Next()) { + contents = (*iter)->tab_strip_model()->GetActiveWebContents(); + if (contents && contents->GetMainFrame() && + contents->GetMainFrame()->GetVisibilityState() == + blink::WebPageVisibilityStateVisible) { + break; + } + } + + if (contents) { + // Give the page time to finish loading. + const int kLongerDelayMins = 3; + Observe(contents); + delay = base::TimeDelta::FromMinutes(kLongerDelayMins); + } +#else + // TODO(michaeln): We should probably monitor the initial page load here too, + // but since ChromeBrowserMainExtraPartsMetrics doesn't, not doing that yet. + const int kAndroidDelaySecs = 10; + delay = base::TimeDelta::FromSeconds(kAndroidDelaySecs); +#endif // !defined(OS_ANDROID) + + BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE, + base::Bind(&StartupObserver::OnFailsafeTimeout, + weak_factory_.GetWeakPtr()), + delay); +} + +} // namespace + +void AfterStartupTaskUtils::StartMonitoringStartup() { + // The observer is self-deleting. + (new StartupObserver)->Start(); +} + +void AfterStartupTaskUtils::PostTask( + const tracked_objects::Location& from_here, + const scoped_refptr<base::TaskRunner>& task_runner, + const base::Closure& task) { + if (IsBrowserStartupComplete()) { + task_runner->PostTask(from_here, task); + return; + } + + scoped_ptr<AfterStartupTask> queued_task( + new AfterStartupTask(from_here, task_runner, task)); + QueueTask(queued_task.Pass()); +} + +void AfterStartupTaskUtils::SetBrowserStartupIsComplete() { + ::SetBrowserStartupIsComplete(); +} + +bool AfterStartupTaskUtils::IsBrowserStartupComplete() { + return ::IsBrowserStartupComplete(); +} + +void AfterStartupTaskUtils::UnsafeResetForTesting() { + DCHECK(g_after_startup_tasks.Get().empty()); + if (!IsBrowserStartupComplete()) + return; + g_startup_complete_flag.Get().UnsafeResetForTesting(); + DCHECK(!IsBrowserStartupComplete()); +}
diff --git a/chrome/browser/after_startup_task_utils.h b/chrome/browser/after_startup_task_utils.h new file mode 100644 index 0000000..6c56fd3 --- /dev/null +++ b/chrome/browser/after_startup_task_utils.h
@@ -0,0 +1,44 @@ +// 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_AFTER_STARTUP_TASK_UTILS_H_ +#define CHROME_BROWSER_AFTER_STARTUP_TASK_UTILS_H_ + +#include "base/basictypes.h" +#include "base/bind.h" +#include "base/gtest_prod_util.h" +#include "base/memory/ref_counted.h" + +namespace base { +class TaskRunner; +} +namespace tracked_objects { +class Location; +}; + +class AfterStartupTaskUtils { + public: + // Observes startup and when complete runs tasks that have accrued. + static void StartMonitoringStartup(); + + // Used to augment the behavior of BrowserThread::PostAfterStartupTask + // for chrome. Tasks are queued until startup is complete. + // Note: see browser_thread.h + static void PostTask(const tracked_objects::Location& from_here, + const scoped_refptr<base::TaskRunner>& task_runner, + const base::Closure& task); + + private: + friend class AfterStartupTaskTest; + FRIEND_TEST_ALL_PREFIXES(AfterStartupTaskTest, IsStartupComplete); + FRIEND_TEST_ALL_PREFIXES(AfterStartupTaskTest, PostTask); + + static bool IsBrowserStartupComplete(); + static void SetBrowserStartupIsComplete(); + static void UnsafeResetForTesting(); + + DISALLOW_IMPLICIT_CONSTRUCTORS(AfterStartupTaskUtils); +}; + +#endif // CHROME_BROWSER_AFTER_STARTUP_TASK_UTILS_H_
diff --git a/chrome/browser/after_startup_task_utils_unittest.cc b/chrome/browser/after_startup_task_utils_unittest.cc new file mode 100644 index 0000000..bc6971d --- /dev/null +++ b/chrome/browser/after_startup_task_utils_unittest.cc
@@ -0,0 +1,199 @@ +// 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/after_startup_task_utils.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop.h" +#include "base/message_loop/message_loop_proxy.h" +#include "base/run_loop.h" +#include "base/task_runner_util.h" +#include "base/threading/thread.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "testing/gtest/include/gtest/gtest.h" + +using base::RunLoop; +using content::BrowserThread; +using content::TestBrowserThreadBundle; + +namespace { + +class WrappedTaskRunner : public base::TaskRunner { + public: + explicit WrappedTaskRunner(const scoped_refptr<TaskRunner>& real_runner) + : real_task_runner_(real_runner) {} + + bool PostDelayedTask(const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) override { + ++posted_task_count_; + return real_task_runner_->PostDelayedTask( + from_here, base::Bind(&WrappedTaskRunner::RunWrappedTask, this, task), + base::TimeDelta()); // Squash all delays so our tests complete asap. + } + + bool RunsTasksOnCurrentThread() const override { + return real_task_runner_->RunsTasksOnCurrentThread(); + } + + base::TaskRunner* real_runner() const { return real_task_runner_.get(); } + + int total_task_count() const { return posted_task_count_ + ran_task_count_; } + int posted_task_count() const { return posted_task_count_; } + int ran_task_count() const { return ran_task_count_; } + + void reset_task_counts() { + posted_task_count_ = 0; + ran_task_count_ = 0; + } + + private: + ~WrappedTaskRunner() override {} + + void RunWrappedTask(const base::Closure& task) { + ++ran_task_count_; + task.Run(); + } + + scoped_refptr<TaskRunner> real_task_runner_; + int posted_task_count_ = 0; + int ran_task_count_ = 0; +}; + +} // namespace + +class AfterStartupTaskTest : public testing::Test { + public: + AfterStartupTaskTest() + : browser_thread_bundle_(TestBrowserThreadBundle::REAL_DB_THREAD) { + ui_thread_ = new WrappedTaskRunner( + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI)); + db_thread_ = new WrappedTaskRunner( + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB)); + AfterStartupTaskUtils::UnsafeResetForTesting(); + } + + // Hop to the db thread and call IsBrowserStartupComplete. + bool GetIsBrowserStartupCompleteFromDBThread() { + RunLoop run_loop; + bool is_complete; + base::PostTaskAndReplyWithResult( + db_thread_->real_runner(), FROM_HERE, + base::Bind(&AfterStartupTaskUtils::IsBrowserStartupComplete), + base::Bind(&AfterStartupTaskTest::GotIsOnBrowserStartupComplete, + &run_loop, &is_complete)); + run_loop.Run(); + return is_complete; + } + + // Hop to the db thread and call PostAfterStartupTask. + void PostAfterStartupTaskFromDBThread( + const tracked_objects::Location& from_here, + const scoped_refptr<base::TaskRunner>& task_runner, + const base::Closure& task) { + RunLoop run_loop; + db_thread_->real_runner()->PostTaskAndReply( + FROM_HERE, base::Bind(&AfterStartupTaskUtils::PostTask, from_here, + task_runner, task), + base::Bind(&RunLoop::Quit, base::Unretained(&run_loop))); + run_loop.Run(); + } + + // Make sure all tasks posted to the DB thread get run. + void FlushDBThread() { + RunLoop run_loop; + db_thread_->real_runner()->PostTaskAndReply( + FROM_HERE, base::Bind(&base::DoNothing), + base::Bind(&RunLoop::Quit, base::Unretained(&run_loop))); + run_loop.Run(); + } + + static void VerifyExpectedThread(BrowserThread::ID id) { + EXPECT_TRUE(BrowserThread::CurrentlyOn(id)); + } + + protected: + scoped_refptr<WrappedTaskRunner> ui_thread_; + scoped_refptr<WrappedTaskRunner> db_thread_; + + private: + static void GotIsOnBrowserStartupComplete(RunLoop* loop, + bool* out, + bool is_complete) { + *out = is_complete; + loop->Quit(); + } + + TestBrowserThreadBundle browser_thread_bundle_; +}; + +TEST_F(AfterStartupTaskTest, IsStartupComplete) { + // Check IsBrowserStartupComplete on a background thread first to + // verify that it does not allocate the underlying flag on that thread. + // That allocation thread correctness part of this test relies on + // the DCHECK in CancellationFlag::Set(). + EXPECT_FALSE(GetIsBrowserStartupCompleteFromDBThread()); + EXPECT_FALSE(AfterStartupTaskUtils::IsBrowserStartupComplete()); + AfterStartupTaskUtils::SetBrowserStartupIsComplete(); + EXPECT_TRUE(AfterStartupTaskUtils::IsBrowserStartupComplete()); + EXPECT_TRUE(GetIsBrowserStartupCompleteFromDBThread()); +} + +TEST_F(AfterStartupTaskTest, PostTask) { + // Nothing should be posted prior to startup completion. + EXPECT_FALSE(AfterStartupTaskUtils::IsBrowserStartupComplete()); + AfterStartupTaskUtils::PostTask( + FROM_HERE, ui_thread_, + base::Bind(&AfterStartupTaskTest::VerifyExpectedThread, + BrowserThread::UI)); + AfterStartupTaskUtils::PostTask( + FROM_HERE, db_thread_, + base::Bind(&AfterStartupTaskTest::VerifyExpectedThread, + BrowserThread::DB)); + PostAfterStartupTaskFromDBThread( + FROM_HERE, ui_thread_, + base::Bind(&AfterStartupTaskTest::VerifyExpectedThread, + BrowserThread::UI)); + PostAfterStartupTaskFromDBThread( + FROM_HERE, db_thread_, + base::Bind(&AfterStartupTaskTest::VerifyExpectedThread, + BrowserThread::DB)); + RunLoop().RunUntilIdle(); + EXPECT_EQ(0, db_thread_->total_task_count() + ui_thread_->total_task_count()); + + // Queued tasks should be posted upon setting the flag. + AfterStartupTaskUtils::SetBrowserStartupIsComplete(); + EXPECT_EQ(2, db_thread_->posted_task_count()); + EXPECT_EQ(2, ui_thread_->posted_task_count()); + FlushDBThread(); + RunLoop().RunUntilIdle(); + EXPECT_EQ(2, db_thread_->ran_task_count()); + EXPECT_EQ(2, ui_thread_->ran_task_count()); + + db_thread_->reset_task_counts(); + ui_thread_->reset_task_counts(); + EXPECT_EQ(0, db_thread_->total_task_count() + ui_thread_->total_task_count()); + + // Tasks posted after startup should get posted immediately. + AfterStartupTaskUtils::PostTask(FROM_HERE, ui_thread_, + base::Bind(&base::DoNothing)); + AfterStartupTaskUtils::PostTask(FROM_HERE, db_thread_, + base::Bind(&base::DoNothing)); + EXPECT_EQ(1, db_thread_->posted_task_count()); + EXPECT_EQ(1, ui_thread_->posted_task_count()); + PostAfterStartupTaskFromDBThread(FROM_HERE, ui_thread_, + base::Bind(&base::DoNothing)); + PostAfterStartupTaskFromDBThread(FROM_HERE, db_thread_, + base::Bind(&base::DoNothing)); + EXPECT_EQ(2, db_thread_->posted_task_count()); + EXPECT_EQ(2, ui_thread_->posted_task_count()); + FlushDBThread(); + RunLoop().RunUntilIdle(); + EXPECT_EQ(2, db_thread_->ran_task_count()); + EXPECT_EQ(2, ui_thread_->ran_task_count()); +}
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc index 5172935..750604c 100644 --- a/chrome/browser/apps/guest_view/web_view_browsertest.cc +++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -9,6 +9,7 @@ #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/apps/app_browsertest_util.h" #include "chrome/browser/chrome_content_browser_client.h" +#include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/prerender/prerender_link_manager.h" #include "chrome/browser/prerender/prerender_link_manager_factory.h" #include "chrome/browser/profiles/profile.h" @@ -712,6 +713,38 @@ return guest_web_contents; } + // Helper to load interstitial page in a <webview>. + void InterstitialTeardownTestHelper() { + // Start a HTTPS server so we can load an interstitial page inside guest. + net::SpawnedTestServer::SSLOptions ssl_options; + ssl_options.server_certificate = + net::SpawnedTestServer::SSLOptions::CERT_MISMATCHED_NAME; + net::SpawnedTestServer https_server( + net::SpawnedTestServer::TYPE_HTTPS, ssl_options, + base::FilePath(FILE_PATH_LITERAL("chrome/test/data"))); + ASSERT_TRUE(https_server.Start()); + + net::HostPortPair host_and_port = https_server.host_port_pair(); + + LoadAndLaunchPlatformApp("web_view/interstitial_teardown", + "EmbedderLoaded"); + + // Now load the guest. + content::WebContents* embedder_web_contents = + GetFirstAppWindowWebContents(); + ExtensionTestMessageListener second("GuestAddedToDom", false); + EXPECT_TRUE(content::ExecuteScript( + embedder_web_contents, + base::StringPrintf("loadGuest(%d);\n", host_and_port.port()))); + ASSERT_TRUE(second.WaitUntilSatisfied()); + + // Wait for interstitial page to be shown in guest. + content::WebContents* guest_web_contents = + GetGuestViewManager()->WaitForSingleGuestCreated(); + ASSERT_TRUE(guest_web_contents->GetRenderProcessHost()->IsIsolatedGuest()); + content::WaitForInterstitialAttach(guest_web_contents); + } + // Runs media_access/allow tests. void MediaAccessAPIAllowTestHelper(const std::string& test_name); @@ -1337,8 +1370,8 @@ NO_TEST_SERVER); } -// This test makes sure we do not crash if app is closed while interstitial -// page is being shown in guest. +// This test makes sure the browser process does not crash if app is closed +// while an interstitial page is being shown in guest. IN_PROC_BROWSER_TEST_F(WebViewTest, InterstitialTeardown) { #if defined(OS_WIN) // Flaky on XP bot http://crbug.com/297014 @@ -1346,38 +1379,35 @@ return; #endif - // Start a HTTPS server so we can load an interstitial page inside guest. - net::SpawnedTestServer::SSLOptions ssl_options; - ssl_options.server_certificate = - net::SpawnedTestServer::SSLOptions::CERT_MISMATCHED_NAME; - net::SpawnedTestServer https_server( - net::SpawnedTestServer::TYPE_HTTPS, ssl_options, - base::FilePath(FILE_PATH_LITERAL("chrome/test/data"))); - ASSERT_TRUE(https_server.Start()); - - net::HostPortPair host_and_port = https_server.host_port_pair(); - - LoadAndLaunchPlatformApp("web_view/interstitial_teardown", "EmbedderLoaded"); - - // Now load the guest. - content::WebContents* embedder_web_contents = GetFirstAppWindowWebContents(); - ExtensionTestMessageListener second("GuestAddedToDom", false); - EXPECT_TRUE(content::ExecuteScript( - embedder_web_contents, - base::StringPrintf("loadGuest(%d);\n", host_and_port.port()))); - ASSERT_TRUE(second.WaitUntilSatisfied()); - - // Wait for interstitial page to be shown in guest. - content::WebContents* guest_web_contents = - GetGuestViewManager()->WaitForSingleGuestCreated(); - ASSERT_TRUE(guest_web_contents->GetRenderProcessHost()->IsIsolatedGuest()); - content::WaitForInterstitialAttach(guest_web_contents); + InterstitialTeardownTestHelper(); // Now close the app while interstitial page being shown in guest. extensions::AppWindow* window = GetFirstAppWindow(); window->GetBaseWindow()->Close(); } +// This test makes sure the browser process does not crash if browser is shut +// down while an interstitial page is being shown in guest. +IN_PROC_BROWSER_TEST_F(WebViewTest, InterstitialTeardownOnBrowserShutdown) { +#if defined(OS_WIN) + // http://crbug.com/297014 + if (base::win::GetVersion() <= base::win::VERSION_XP) + return; +#endif + + InterstitialTeardownTestHelper(); + + // Now close the app while interstitial page being shown in guest. + extensions::AppWindow* window = GetFirstAppWindow(); + window->GetBaseWindow()->Close(); + + // InterstitialPage is not destroyed immediately, so the + // RenderWidgetHostViewGuest for it is still there, closing all + // renderer processes will cause the RWHVGuest's RenderProcessGone() + // shutdown path to be exercised. + chrome::CloseAllBrowsers(); +} + IN_PROC_BROWSER_TEST_F(WebViewTest, ShimSrcAttribute) { ASSERT_TRUE(RunPlatformAppTest("platform_apps/web_view/src_attribute")) << message_;
diff --git a/chrome/browser/bookmarks/enhanced_bookmarks_features.cc b/chrome/browser/bookmarks/enhanced_bookmarks_features.cc index 8f69f07..bbe6335 100644 --- a/chrome/browser/bookmarks/enhanced_bookmarks_features.cc +++ b/chrome/browser/bookmarks/enhanced_bookmarks_features.cc
@@ -14,10 +14,6 @@ #include "extensions/common/features/feature_provider.h" #endif // !defined(OS_ANDROID) && !defined(OS_IOS) -#if defined(OS_ANDROID) -#include "base/android/build_info.h" -#endif // defined(OS_ANDROID) - namespace { const char kFieldTrialName[] = "EnhancedBookmarks"; @@ -75,10 +71,6 @@ bool opt_out = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( switches::kEnhancedBookmarksExperiment) == "0"; -#if defined(OS_ANDROID) - opt_out |= base::android::BuildInfo::GetInstance()->sdk_int() < - base::android::SdkVersion::SDK_VERSION_ICE_CREAM_SANDWICH_MR1; -#endif // defined(OS_ANDROID) if (opt_out) return false;
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc index b373810..254d2ef9 100644 --- a/chrome/browser/browser_process_impl.cc +++ b/chrome/browser/browser_process_impl.cc
@@ -152,7 +152,7 @@ static const int kUpdateCheckIntervalHours = 6; #endif -#if defined(USE_X11) || defined(OS_WIN) +#if defined(USE_X11) || defined(OS_WIN) || defined(USE_OZONE) // How long to wait for the File thread to complete during EndSession, on Linux // and Windows. We have a timeout here because we're unable to run the UI // messageloop and there's some deadlock risk. Our only option is to exit @@ -498,7 +498,7 @@ // // If you change the condition here, be sure to also change // ProfileBrowserTests to match. -#if defined(USE_X11) || defined(OS_WIN) +#if defined(USE_X11) || defined(OS_WIN) || defined(USE_OZONE) // Do a best-effort wait on the successful countdown of rundown tasks. Note // that if we don't complete "quickly enough", Windows will terminate our // process.
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index 7d3a50a..f42f31f8 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc
@@ -39,6 +39,7 @@ #include "build/build_config.h" #include "cc/base/switches.h" #include "chrome/browser/about_flags.h" +#include "chrome/browser/after_startup_task_utils.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_impl.h" #include "chrome/browser/browser_process_platform_part.h" @@ -1127,6 +1128,13 @@ base::Bind(&WebRtcLogUtil::DeleteOldWebRtcLogFilesForAllProfiles), base::TimeDelta::FromMinutes(1)); #endif // defined(ENABLE_WEBRTC) + + // At this point, StartupBrowserCreator::Start has run creating initial + // browser windows and tabs, but no progress has been made in loading + // content as the main message loop hasn't started processing tasks yet. + // We setup to observe to the initial page load here to defer running + // task posted via PostAfterStartupTask until its complete. + AfterStartupTaskUtils::StartMonitoringStartup(); } int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() {
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 1c16189..2617765 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -20,6 +20,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/threading/sequenced_worker_pool.h" +#include "chrome/browser/after_startup_task_utils.h" #include "chrome/browser/browser_about_handler.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_shutdown.h" @@ -720,6 +721,13 @@ return main_parts; } +void ChromeContentBrowserClient::PostAfterStartupTask( + const tracked_objects::Location& from_here, + const scoped_refptr<base::TaskRunner>& task_runner, + const base::Closure& task) { + AfterStartupTaskUtils::PostTask(from_here, task_runner, task); +} + std::string ChromeContentBrowserClient::GetStoragePartitionIdForSite( content::BrowserContext* browser_context, const GURL& site) {
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index 6af499c3..2f23b384 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h
@@ -50,6 +50,9 @@ content::BrowserMainParts* CreateBrowserMainParts( const content::MainFunctionParams& parameters) override; + void PostAfterStartupTask(const tracked_objects::Location& from_here, + const scoped_refptr<base::TaskRunner>& task_runner, + const base::Closure& task) override; std::string GetStoragePartitionIdForSite( content::BrowserContext* browser_context, const GURL& site) override; @@ -241,9 +244,8 @@ content::FileDescriptorInfo* mappings) override; #endif #if defined(OS_WIN) - virtual const wchar_t* GetResourceDllName() override; - virtual void PreSpawnRenderer(sandbox::TargetPolicy* policy, - bool* success) override; + const wchar_t* GetResourceDllName() override; + void PreSpawnRenderer(sandbox::TargetPolicy* policy, bool* success) override; #endif bool CheckMediaAccessPermission(content::BrowserContext* browser_context, const GURL& security_origin,
diff --git a/chrome/browser/chromeos/fileapi/file_system_backend.cc b/chrome/browser/chromeos/fileapi/file_system_backend.cc index 96f88bd..17f1443 100644 --- a/chrome/browser/chromeos/fileapi/file_system_backend.cc +++ b/chrome/browser/chromeos/fileapi/file_system_backend.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/chromeos/fileapi/file_system_backend.h" +#include "base/command_line.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/strings/stringprintf.h" @@ -11,6 +12,7 @@ #include "chrome/browser/chromeos/fileapi/file_system_backend_delegate.h" #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h" #include "chrome/common/url_constants.h" +#include "chromeos/chromeos_switches.h" #include "chromeos/dbus/cros_disks_client.h" #include "storage/browser/fileapi/async_file_util.h" #include "storage/browser/fileapi/external_mount_points.h" @@ -243,6 +245,13 @@ if (type == storage::kFileSystemTypeProvided) return file_system_provider_delegate_->GetWatcherManager(type); + // Enables MTP file watcher only when MTP write support is enabled. + if (type == storage::kFileSystemTypeDeviceMediaAsFileStorage && + base::CommandLine::ForCurrentProcess()->HasSwitch( + chromeos::switches::kEnableMtpWriteSupport)) { + return mtp_delegate_->GetWatcherManager(type); + } + // TODO(mtomasz): Add support for other backends. return NULL; }
diff --git a/chrome/browser/chromeos/fileapi/mtp_file_system_backend_delegate.cc b/chrome/browser/chromeos/fileapi/mtp_file_system_backend_delegate.cc index 39a4955..e0b88eb 100644 --- a/chrome/browser/chromeos/fileapi/mtp_file_system_backend_delegate.cc +++ b/chrome/browser/chromeos/fileapi/mtp_file_system_backend_delegate.cc
@@ -14,7 +14,9 @@ const base::FilePath& storage_partition_path) : device_media_async_file_util_( DeviceMediaAsyncFileUtil::Create(storage_partition_path, - NO_MEDIA_FILE_VALIDATION)) { + NO_MEDIA_FILE_VALIDATION)), + mtp_watcher_manager_( + new MTPWatcherManager(device_media_async_file_util_.get())) { } MTPFileSystemBackendDelegate::~MTPFileSystemBackendDelegate() { @@ -53,8 +55,8 @@ storage::WatcherManager* MTPFileSystemBackendDelegate::GetWatcherManager( storage::FileSystemType type) { - NOTIMPLEMENTED(); - return NULL; + DCHECK_EQ(storage::kFileSystemTypeDeviceMediaAsFileStorage, type); + return mtp_watcher_manager_.get(); } void MTPFileSystemBackendDelegate::GetRedirectURLForContents(
diff --git a/chrome/browser/chromeos/fileapi/mtp_file_system_backend_delegate.h b/chrome/browser/chromeos/fileapi/mtp_file_system_backend_delegate.h index e49add0..6a6d3f34 100644 --- a/chrome/browser/chromeos/fileapi/mtp_file_system_backend_delegate.h +++ b/chrome/browser/chromeos/fileapi/mtp_file_system_backend_delegate.h
@@ -7,6 +7,7 @@ #include "base/memory/scoped_ptr.h" #include "chrome/browser/chromeos/fileapi/file_system_backend_delegate.h" +#include "chrome/browser/chromeos/fileapi/mtp_watcher_manager.h" namespace base { class FilePath; @@ -53,6 +54,7 @@ private: scoped_ptr<DeviceMediaAsyncFileUtil> device_media_async_file_util_; + scoped_ptr<MTPWatcherManager> mtp_watcher_manager_; DISALLOW_COPY_AND_ASSIGN(MTPFileSystemBackendDelegate); };
diff --git a/chrome/browser/chromeos/fileapi/mtp_watcher_manager.cc b/chrome/browser/chromeos/fileapi/mtp_watcher_manager.cc new file mode 100644 index 0000000..58439f8e --- /dev/null +++ b/chrome/browser/chromeos/fileapi/mtp_watcher_manager.cc
@@ -0,0 +1,33 @@ +// 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/fileapi/mtp_watcher_manager.h" + +namespace chromeos { + +MTPWatcherManager::MTPWatcherManager( + DeviceMediaAsyncFileUtil* device_media_async_file_util) + : device_media_async_file_util_(device_media_async_file_util) { + DCHECK(device_media_async_file_util != NULL); +} + +MTPWatcherManager::~MTPWatcherManager() { +} + +void MTPWatcherManager::AddWatcher( + const storage::FileSystemURL& url, + bool recursive, + const StatusCallback& callback, + const NotificationCallback& notification_callback) { + device_media_async_file_util_->AddWatcher(url, recursive, callback, + notification_callback); +} + +void MTPWatcherManager::RemoveWatcher(const storage::FileSystemURL& url, + bool recursive, + const StatusCallback& callback) { + device_media_async_file_util_->RemoveWatcher(url, recursive, callback); +} + +} // namespace chromeos
diff --git a/chrome/browser/chromeos/fileapi/mtp_watcher_manager.h b/chrome/browser/chromeos/fileapi/mtp_watcher_manager.h new file mode 100644 index 0000000..613d5ee --- /dev/null +++ b/chrome/browser/chromeos/fileapi/mtp_watcher_manager.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_CHROMEOS_FILEAPI_MTP_WATCHER_MANAGER_H_ +#define CHROME_BROWSER_CHROMEOS_FILEAPI_MTP_WATCHER_MANAGER_H_ + +#include "chrome/browser/media_galleries/fileapi/device_media_async_file_util.h" +#include "storage/browser/fileapi/watcher_manager.h" + +namespace storage { + +class FileSystemURL; + +} // namespace storage + +namespace chromeos { + +class MTPWatcherManager : public storage::WatcherManager { + public: + explicit MTPWatcherManager( + DeviceMediaAsyncFileUtil* device_media_async_file_util); + ~MTPWatcherManager() override; + + void AddWatcher(const storage::FileSystemURL& url, + bool recursive, + const StatusCallback& callback, + const NotificationCallback& notification_callback) override; + + void RemoveWatcher(const storage::FileSystemURL& url, + bool recursive, + const StatusCallback& callback) override; + + private: + DeviceMediaAsyncFileUtil* const device_media_async_file_util_; +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_FILEAPI_MTP_WATCHER_MANAGER_H_
diff --git a/chrome/browser/component_updater/chrome_component_updater_configurator.cc b/chrome/browser/component_updater/chrome_component_updater_configurator.cc index 36f602d..f4019220 100644 --- a/chrome/browser/component_updater/chrome_component_updater_configurator.cc +++ b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
@@ -17,6 +17,7 @@ #endif // OS_WIN #include "build/build_config.h" #include "chrome/browser/component_updater/component_patcher_operation_out_of_process.h" +#include "chrome/browser/component_updater/url_constants.h" #include "chrome/browser/update_client/chrome_update_query_params_delegate.h" #include "chrome/common/chrome_version_info.h" #include "components/component_updater/component_updater_switches.h" @@ -50,17 +51,6 @@ // Sets the URL for updates. const char kSwitchUrlSource[] = "url-source"; -#define COMPONENT_UPDATER_SERVICE_ENDPOINT \ - "//clients2.google.com/service/update2" - -// The default URL for the v3 protocol service endpoint. In some cases, the -// component updater is allowed to fall back to and alternate URL source, if -// the request to the default URL source fails. -// The value of |kDefaultUrlSource| can be overridden with -// --component-updater=url-source=someurl. -const char kDefaultUrlSource[] = "https:" COMPONENT_UPDATER_SERVICE_ENDPOINT; -const char kAltUrlSource[] = "http:" COMPONENT_UPDATER_SERVICE_ENDPOINT; - // Disables differential updates. const char kSwitchDisableDeltaUpdates[] = "disable-delta-updates"; @@ -218,9 +208,9 @@ if (url_source_override_.is_valid()) { urls.push_back(GURL(url_source_override_)); } else { - urls.push_back(GURL(kDefaultUrlSource)); + urls.push_back(GURL(kUpdaterDefaultUrl)); if (fallback_to_alt_source_url_enabled_) { - urls.push_back(GURL(kAltUrlSource)); + urls.push_back(GURL(kUpdaterAltUrl)); } } return urls;
diff --git a/chrome/browser/component_updater/url_constants.cc b/chrome/browser/component_updater/url_constants.cc new file mode 100644 index 0000000..a27f21a --- /dev/null +++ b/chrome/browser/component_updater/url_constants.cc
@@ -0,0 +1,19 @@ +// 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/component_updater/url_constants.h" + +namespace component_updater { + +// The alternative URL for the v3 protocol service endpoint. +const char kUpdaterAltUrl[] = "http://clients2.google.com/service/update2"; + +// The default URL for the v3 protocol service endpoint. In some cases, the +// component updater is allowed to fall back to and alternate URL source, if +// the request to the default URL source fails. +// The value of |kDefaultUrlSource| can be overridden with +// --component-updater=url-source=someurl. +const char kUpdaterDefaultUrl[] = "https://clients2.google.com/service/update2"; + +} // namespace component_updater
diff --git a/chrome/browser/component_updater/url_constants.h b/chrome/browser/component_updater/url_constants.h new file mode 100644 index 0000000..1c00d70 --- /dev/null +++ b/chrome/browser/component_updater/url_constants.h
@@ -0,0 +1,15 @@ +// 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_COMPONENT_UPDATER_URL_CONSTANTS_H_ +#define CHROME_BROWSER_COMPONENT_UPDATER_URL_CONSTANTS_H_ + +namespace component_updater { + +extern const char kUpdaterAltUrl[]; +extern const char kUpdaterDefaultUrl[]; + +} // namespace component_updater + +#endif // CHROME_BROWSER_COMPONENT_UPDATER_URL_CONSTANTS_H_
diff --git a/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc b/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc index 934e3f5..e502981 100644 --- a/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc +++ b/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
@@ -802,4 +802,91 @@ normal_provider.ShutdownOnUIThread(); } +TEST(PrefProviderTest, ClearAllContentSettingsRules) { + TestingPrefServiceSyncable prefs; + PrefProvider::RegisterProfilePrefs(prefs.registry()); + + ContentSettingsPattern pattern = + ContentSettingsPattern::FromString("google.com"); + ContentSettingsPattern wildcard = + ContentSettingsPattern::FromString("*"); + scoped_ptr<base::Value> value( + new base::FundamentalValue(CONTENT_SETTING_ALLOW)); + ResourceIdentifier res_id("abcde"); + + PrefProvider provider(&prefs, false); + + // Non-empty pattern, syncable, empty resource identifier. + provider.SetWebsiteSetting(pattern, wildcard, CONTENT_SETTINGS_TYPE_IMAGES, + ResourceIdentifier(), value->DeepCopy()); + + // Non-empty pattern, non-syncable, empty resource identifier. + provider.SetWebsiteSetting(pattern, wildcard, + CONTENT_SETTINGS_TYPE_GEOLOCATION, + ResourceIdentifier(), value->DeepCopy()); + + // Non-empty pattern, plugins, non-empty resource identifier. + provider.SetWebsiteSetting(pattern, wildcard, CONTENT_SETTINGS_TYPE_PLUGINS, + res_id, value->DeepCopy()); + + // Empty pattern, plugins, non-empty resource identifier. + provider.SetWebsiteSetting(wildcard, wildcard, CONTENT_SETTINGS_TYPE_PLUGINS, + res_id, value->DeepCopy()); + + // Non-empty pattern, syncable, empty resource identifier. + provider.SetWebsiteSetting(pattern, wildcard, CONTENT_SETTINGS_TYPE_COOKIES, + ResourceIdentifier(), value->DeepCopy()); + + // Non-empty pattern, non-syncable, empty resource identifier. + provider.SetWebsiteSetting(pattern, wildcard, + CONTENT_SETTINGS_TYPE_NOTIFICATIONS, + ResourceIdentifier(), value->DeepCopy()); + + provider.ClearAllContentSettingsRules(CONTENT_SETTINGS_TYPE_IMAGES); + provider.ClearAllContentSettingsRules(CONTENT_SETTINGS_TYPE_GEOLOCATION); + provider.ClearAllContentSettingsRules(CONTENT_SETTINGS_TYPE_PLUGINS); + + // Test that the new preferences for images, geolocation and plugins + // are empty. + const char* empty_prefs[] = { + prefs::kContentSettingsImagesPatternPairs, + prefs::kContentSettingsGeolocationPatternPairs, + prefs::kContentSettingsPluginsPatternPairs + }; + + for (const char* pref : empty_prefs) { + DictionaryPrefUpdate update(&prefs, pref); + const base::DictionaryValue* dictionary = update.Get(); + EXPECT_TRUE(dictionary->empty()); + } + + // Test that the preferences for cookies and notifications are not empty. + const char* nonempty_prefs[] = { + prefs::kContentSettingsCookiesPatternPairs, + prefs::kContentSettingsNotificationsPatternPairs + }; + + for (const char* pref : nonempty_prefs) { + DictionaryPrefUpdate update(&prefs, pref); + const base::DictionaryValue* dictionary = update.Get(); + EXPECT_EQ(1u, dictionary->size()); + } + + // Test that the old preference only contains cookies and notifications. + { + DictionaryPrefUpdate update(&prefs, prefs::kContentSettingsPatternPairs); + const base::DictionaryValue* dictionary = update.Get(); + const base::DictionaryValue* exception; + EXPECT_TRUE(dictionary->GetDictionaryWithoutPathExpansion( + CreatePatternString(pattern, wildcard), &exception)); + EXPECT_EQ(1u, exception->size()); + EXPECT_TRUE(exception->HasKey(GetTypeName(CONTENT_SETTINGS_TYPE_COOKIES))); + + // The notification setting was not cleared, but it was also never written + // to the old preference, as it is unsyncable. + } + + provider.ShutdownOnUIThread(); +} + } // namespace content_settings
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 75b13769..dc14204 100644 --- a/chrome/browser/content_settings/host_content_settings_map_unittest.cc +++ b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
@@ -708,14 +708,14 @@ TestingProfile profile; scoped_ptr<base::Value> value(base::JSONReader::Read( - "{\"[*.]\\xC4\\x87ira.com,*\":{\"setting\":1}}")); - profile.GetPrefs()->Set(prefs::kContentSettingsImagesPatternPairs, *value); + "{\"[*.]\\xC4\\x87ira.com,*\":{\"images\":1}}")); + profile.GetPrefs()->Set(prefs::kContentSettingsPatternPairs, *value); // Set punycode equivalent, with different setting. scoped_ptr<base::Value> puny_value(base::JSONReader::Read( - "{\"[*.]xn--ira-ppa.com,*\":{\"setting\":2}}")); + "{\"[*.]xn--ira-ppa.com,*\":{\"images\":2}}")); profile.GetPrefs()->Set( - prefs::kContentSettingsImagesPatternPairs, *puny_value); + prefs::kContentSettingsPatternPairs, *puny_value); // Initialize the content map. profile.GetHostContentSettingsMap();
diff --git a/chrome/browser/devtools/chrome_devtools_manager_delegate.cc b/chrome/browser/devtools/chrome_devtools_manager_delegate.cc index 1529f26..81f354d 100644 --- a/chrome/browser/devtools/chrome_devtools_manager_delegate.cc +++ b/chrome/browser/devtools/chrome_devtools_manager_delegate.cc
@@ -27,7 +27,9 @@ void ChromeDevToolsManagerDelegate::Inspect( content::BrowserContext* browser_context, content::DevToolsAgentHost* agent_host) { - if (!agent_host->IsWorker()) { + content::DevToolsAgentHost::Type type = agent_host->GetType(); + if (type != content::DevToolsAgentHost::TYPE_SHARED_WORKER && + type != content::DevToolsAgentHost::TYPE_SERVICE_WORKER) { // TODO(horo): Support other types of DevToolsAgentHost when necessary. NOTREACHED() << "Inspect() only supports workers."; }
diff --git a/chrome/browser/devtools/devtools_embedder_message_dispatcher.cc b/chrome/browser/devtools/devtools_embedder_message_dispatcher.cc index 6d4358d..0534993 100644 --- a/chrome/browser/devtools/devtools_embedder_message_dispatcher.cc +++ b/chrome/browser/devtools/devtools_embedder_message_dispatcher.cc
@@ -194,5 +194,13 @@ &Delegate::RecordEnumeratedHistogram, delegate); d->RegisterHandlerWithCallback("sendJsonRequest", &Delegate::SendJsonRequest, delegate); + d->RegisterHandlerWithCallback("getPreferences", + &Delegate::GetPreferences, delegate); + d->RegisterHandler("setPreference", + &Delegate::SetPreference, delegate); + d->RegisterHandler("removePreference", + &Delegate::RemovePreference, delegate); + d->RegisterHandler("clearPreferences", + &Delegate::ClearPreferences, delegate); return d; }
diff --git a/chrome/browser/devtools/devtools_embedder_message_dispatcher.h b/chrome/browser/devtools/devtools_embedder_message_dispatcher.h index 882bce6..badf46f 100644 --- a/chrome/browser/devtools/devtools_embedder_message_dispatcher.h +++ b/chrome/browser/devtools/devtools_embedder_message_dispatcher.h
@@ -66,6 +66,11 @@ virtual void ZoomOut() = 0; virtual void ResetZoom() = 0; virtual void SetDevicesUpdatesEnabled(bool enabled) = 0; + virtual void GetPreferences(const DispatchCallback& callback) = 0; + virtual void SetPreference(const std::string& name, + const std::string& value) = 0; + virtual void RemovePreference(const std::string& name) = 0; + virtual void ClearPreferences() = 0; virtual void SendMessageToBrowser(const std::string& message) = 0; virtual void RecordEnumeratedHistogram(const std::string& name, int sample,
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc index 294b9c2..3f751d3 100644 --- a/chrome/browser/devtools/devtools_ui_bindings.cc +++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -8,6 +8,7 @@ #include "base/json/json_reader.h" #include "base/json/json_writer.h" #include "base/metrics/histogram.h" +#include "base/prefs/scoped_user_pref_update.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" @@ -17,6 +18,7 @@ #include "chrome/browser/devtools/devtools_target_impl.h" #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h" #include "chrome/browser/infobars/infobar_service.h" +#include "chrome/browser/prefs/pref_service_syncable.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/themes/theme_properties.h" #include "chrome/browser/themes/theme_service.h" @@ -28,6 +30,7 @@ #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/chrome_manifest_url_handlers.h" +#include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" #include "chrome/grit/generated_resources.h" #include "components/infobars/core/confirm_infobar_delegate.h" @@ -205,6 +208,8 @@ void SetIsDocked(bool is_docked) override {} void OpenInNewTab(const std::string& url) override; void SetWhitelistedShortcuts(const std::string& message) override {} + using DispatchCallback = + DevToolsEmbedderMessageDispatcher::Delegate::DispatchCallback; void InspectedContentsClosing() override; void OnLoadCompleted() override {} @@ -735,6 +740,31 @@ } } +void DevToolsUIBindings::GetPreferences(const DispatchCallback& callback) { + const DictionaryValue* prefs = + profile_->GetPrefs()->GetDictionary(prefs::kDevToolsPreferences); + callback.Run(prefs); +} + +void DevToolsUIBindings::SetPreference(const std::string& name, + const std::string& value) { + DictionaryPrefUpdate update(profile_->GetPrefs(), + prefs::kDevToolsPreferences); + update.Get()->SetStringWithoutPathExpansion(name, value); +} + +void DevToolsUIBindings::RemovePreference(const std::string& name) { + DictionaryPrefUpdate update(profile_->GetPrefs(), + prefs::kDevToolsPreferences); + update.Get()->RemoveWithoutPathExpansion(name, nullptr); +} + +void DevToolsUIBindings::ClearPreferences() { + DictionaryPrefUpdate update(profile_->GetPrefs(), + prefs::kDevToolsPreferences); + update.Get()->Clear(); +} + void DevToolsUIBindings::SendMessageToBrowser(const std::string& message) { if (agent_host_.get()) agent_host_->DispatchProtocolMessage(message);
diff --git a/chrome/browser/devtools/devtools_ui_bindings.h b/chrome/browser/devtools/devtools_ui_bindings.h index 4efe4947..060ac32 100644 --- a/chrome/browser/devtools/devtools_ui_bindings.h +++ b/chrome/browser/devtools/devtools_ui_bindings.h
@@ -138,6 +138,11 @@ void SendJsonRequest(const DispatchCallback& callback, const std::string& browser_id, const std::string& url) override; + void GetPreferences(const DispatchCallback& callback) override; + void SetPreference(const std::string& name, + const std::string& value) override; + void RemovePreference(const std::string& name) override; + void ClearPreferences() override; // net::URLFetcherDelegate overrides. void OnURLFetchComplete(const net::URLFetcher* source) override;
diff --git a/chrome/browser/devtools/devtools_window.cc b/chrome/browser/devtools/devtools_window.cc index 502feb0f..5df0546 100644 --- a/chrome/browser/devtools/devtools_window.cc +++ b/chrome/browser/devtools/devtools_window.cc
@@ -329,6 +329,9 @@ registry->RegisterDictionaryPref( prefs::kDevToolsPortForwardingConfig, user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); + registry->RegisterDictionaryPref( + prefs::kDevToolsPreferences, + user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); } // static
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn index dd89827..a03f0dd 100644 --- a/chrome/browser/extensions/BUILD.gn +++ b/chrome/browser/extensions/BUILD.gn
@@ -207,4 +207,7 @@ if (!use_ozone) { sources -= [ "global_shortcut_listener_ozone.cc" ] } + if (enable_media_router) { + defines += [ "ENABLE_MEDIA_ROUTER=1" ] + } }
diff --git a/chrome/browser/extensions/dev_mode_bubble_controller.cc b/chrome/browser/extensions/dev_mode_bubble_controller.cc index d6914e5..202207c 100644 --- a/chrome/browser/extensions/dev_mode_bubble_controller.cc +++ b/chrome/browser/extensions/dev_mode_bubble_controller.cc
@@ -52,7 +52,6 @@ base::string16 GetActionButtonLabel() const override; base::string16 GetDismissButtonLabel() const override; bool ShouldShowExtensionList() const override; - bool ShouldHighlightExtensions() const override; void LogExtensionCount(size_t count) override; void LogAction( ExtensionMessageBubbleController::BubbleAction action) override; @@ -128,10 +127,6 @@ return false; } -bool DevModeBubbleDelegate::ShouldHighlightExtensions() const { - return true; -} - void DevModeBubbleDelegate::LogExtensionCount(size_t count) { UMA_HISTOGRAM_COUNTS_100( "ExtensionBubble.ExtensionsInDevModeCount", count);
diff --git a/chrome/browser/extensions/events_apitest.cc b/chrome/browser/extensions/events_apitest.cc index 3420022..e70270a2 100644 --- a/chrome/browser/extensions/events_apitest.cc +++ b/chrome/browser/extensions/events_apitest.cc
@@ -4,6 +4,50 @@ #include "chrome/browser/extensions/extension_apitest.h" +#include "extensions/browser/event_router.h" +#include "extensions/browser/extension_registry.h" + +namespace extensions { + IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Events) { ASSERT_TRUE(RunExtensionTest("events")) << message_; } + +// Fails on Win only. http://crbug.com/476863 +#if defined(OS_WIN) +#define MAYBE_EventsAreUnregistered DISABLED_EventsAreUnregistered +#else +#define MAYBE_EventsAreUnregistered EventsAreUnregistered +#endif +// Tests that events are unregistered when an extension page shuts down. +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_EventsAreUnregistered) { + // In this test, page1.html registers for a number of events, then navigates + // to page2.html, which should unregister those events. page2.html notifies + // pass, by which point the event should have been unregistered. + EventRouter* event_router = EventRouter::Get(profile()); + ExtensionRegistry* registry = ExtensionRegistry::Get(profile()); + + std::string test_extension_name = "events_are_unregistered"; + ASSERT_TRUE(RunExtensionSubtest(test_extension_name, "page1.html")) + << message_; + + // Find the extension we just installed by looking for the path. + const Extension* extension = + GetExtensionByPath(registry->enabled_extensions(), + test_data_dir_.AppendASCII(test_extension_name)); + ASSERT_TRUE(extension); + std::string id = extension->id(); + + // The page has closed, so no matter what all events are no longer listened + // to. + EXPECT_FALSE( + event_router->ExtensionHasEventListener(id, "browserAction.onClicked")); + EXPECT_FALSE( + event_router->ExtensionHasEventListener(id, "runtime.onStartup")); + EXPECT_FALSE( + event_router->ExtensionHasEventListener(id, "runtime.onSuspend")); + EXPECT_FALSE( + event_router->ExtensionHasEventListener(id, "runtime.onInstalled")); +} + +} // namespace extensions
diff --git a/chrome/browser/extensions/extension_message_bubble.h b/chrome/browser/extensions/extension_message_bubble.h index 3819a82..71d6e30 100644 --- a/chrome/browser/extensions/extension_message_bubble.h +++ b/chrome/browser/extensions/extension_message_bubble.h
@@ -15,6 +15,16 @@ // controller. class ExtensionMessageBubble { public: + // Setup the callback for when the action button is clicked in the + // bubble. + virtual void OnActionButtonClicked(const base::Closure& callback) = 0; + + // Setup the callback for when the dismiss button is clicked. + virtual void OnDismissButtonClicked(const base::Closure& callback) = 0; + + // Setup the callback for when the link is clicked in the bubble. + virtual void OnLinkClicked(const base::Closure& callback) = 0; + // Instruct the bubble to appear. virtual void Show() = 0; };
diff --git a/chrome/browser/extensions/extension_message_bubble_controller.cc b/chrome/browser/extensions/extension_message_bubble_controller.cc index a30b1f07..778c7ad 100644 --- a/chrome/browser/extensions/extension_message_bubble_controller.cc +++ b/chrome/browser/extensions/extension_message_bubble_controller.cc
@@ -8,7 +8,6 @@ #include "base/metrics/histogram.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/extensions/extension_message_bubble.h" -#include "chrome/browser/extensions/extension_toolbar_model.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" @@ -123,15 +122,21 @@ bool ExtensionMessageBubbleController::CloseOnDeactivate() { return false; } -void ExtensionMessageBubbleController::HighlightExtensionsIfNecessary() { - if (delegate_->ShouldHighlightExtensions()) { - const ExtensionIdList& extension_ids = GetExtensionIdList(); - DCHECK(!extension_ids.empty()); - ExtensionToolbarModel::Get(profile_)->HighlightExtensions(extension_ids); - } -} - void ExtensionMessageBubbleController::Show(ExtensionMessageBubble* bubble) { + // Wire up all the callbacks, to get notified what actions the user took. + base::Closure dismiss_button_callback = + base::Bind(&ExtensionMessageBubbleController::OnBubbleDismiss, + base::Unretained(this)); + base::Closure action_button_callback = + base::Bind(&ExtensionMessageBubbleController::OnBubbleAction, + base::Unretained(this)); + base::Closure link_callback = + base::Bind(&ExtensionMessageBubbleController::OnLinkClicked, + base::Unretained(this)); + bubble->OnActionButtonClicked(action_button_callback); + bubble->OnDismissButtonClicked(dismiss_button_callback); + bubble->OnLinkClicked(link_callback); + bubble->Show(); }
diff --git a/chrome/browser/extensions/extension_message_bubble_controller.h b/chrome/browser/extensions/extension_message_bubble_controller.h index e56ff0c..d932e1d 100644 --- a/chrome/browser/extensions/extension_message_bubble_controller.h +++ b/chrome/browser/extensions/extension_message_bubble_controller.h
@@ -59,10 +59,6 @@ // Whether to show a list of extensions in the bubble. virtual bool ShouldShowExtensionList() const = 0; - // Returns true if the set of affected extensions should be highlighted in - // the toolbar. - virtual bool ShouldHighlightExtensions() const = 0; - // In some cases, we want the delegate only to handle a single extension // and this sets which extension. virtual void RestrictToSingleExtension(const std::string& extension_id); @@ -105,9 +101,6 @@ // Whether to close the bubble when it loses focus. virtual bool CloseOnDeactivate(); - // Highlights the affected extensions if appropriate. - void HighlightExtensionsIfNecessary(); - // Sets up the callbacks and shows the bubble. virtual void Show(ExtensionMessageBubble* bubble);
diff --git a/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc b/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc index 1a50092..40f7c480 100644 --- a/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc +++ b/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc
@@ -33,12 +33,6 @@ #include "extensions/common/value_builder.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(OS_CHROMEOS) -#include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h" -#include "chrome/browser/chromeos/settings/cros_settings.h" -#include "chrome/browser/chromeos/settings/device_settings_service.h" -#endif - namespace { const char kId1[] = "iccfkkhkfiphcjdakkmcjmkfboccmndk"; @@ -213,29 +207,39 @@ BUBBLE_ACTION_CLICK_LINK, }; - FakeExtensionMessageBubble() : controller_(nullptr) {} + FakeExtensionMessageBubble() {} void set_action_on_show(ExtensionBubbleAction action) { action_ = action; } - void set_controller(ExtensionMessageBubbleController* controller) { - controller_ = controller; - } void Show() override { if (action_ == BUBBLE_ACTION_CLICK_ACTION_BUTTON) - controller_->OnBubbleAction(); + action_callback_.Run(); else if (action_ == BUBBLE_ACTION_CLICK_DISMISS_BUTTON) - controller_->OnBubbleDismiss(); + dismiss_callback_.Run(); else if (action_ == BUBBLE_ACTION_CLICK_LINK) - controller_->OnLinkClicked(); + link_callback_.Run(); + } + + void OnActionButtonClicked(const base::Closure& callback) override { + action_callback_ = callback; + } + + void OnDismissButtonClicked(const base::Closure& callback) override { + dismiss_callback_ = callback; + } + + void OnLinkClicked(const base::Closure& callback) override { + link_callback_ = callback; } private: ExtensionBubbleAction action_; - ExtensionMessageBubbleController* controller_; - DISALLOW_COPY_AND_ASSIGN(FakeExtensionMessageBubble); + base::Closure action_callback_; + base::Closure dismiss_callback_; + base::Closure link_callback_; }; class ExtensionMessageBubbleTest : public testing::Test { @@ -386,6 +390,7 @@ void Init() { // The two lines of magical incantation required to get the extension // service to work inside a unit test and access the extension prefs. + thread_bundle_.reset(new content::TestBrowserThreadBundle); profile_.reset(new TestingProfile); static_cast<TestExtensionSystem*>(ExtensionSystem::Get(profile())) ->CreateExtensionService(base::CommandLine::ForCurrentProcess(), @@ -418,22 +423,21 @@ ExtensionService* service_; private: - content::TestBrowserThreadBundle thread_bundle_; scoped_ptr<base::CommandLine> command_line_; + scoped_ptr<content::TestBrowserThreadBundle> thread_bundle_; scoped_ptr<TestingProfile> profile_; -#if defined OS_CHROMEOS - chromeos::ScopedTestDeviceSettingsService test_device_settings_service_; - chromeos::ScopedTestCrosSettings test_cros_settings_; - chromeos::ScopedTestUserManager test_user_manager_; -#endif - DISALLOW_COPY_AND_ASSIGN(ExtensionMessageBubbleTest); }; -// The feature this is meant to test is only enacted on Windows, but it should -// pass on all platforms. -TEST_F(ExtensionMessageBubbleTest, WipeoutControllerTest) { +// The feature this is meant to test is only implemented on Windows. +#if defined(OS_WIN) +#define MAYBE_WipeoutControllerTest WipeoutControllerTest +#else +#define MAYBE_WipeoutControllerTest DISABLED_WipeoutControllerTest +#endif + +TEST_F(ExtensionMessageBubbleTest, MAYBE_WipeoutControllerTest) { Init(); // Add three extensions, and control two of them in this test (extension 1 // and 2). @@ -470,7 +474,6 @@ suspicious_extensions = controller->GetExtensionList(); ASSERT_EQ(1U, suspicious_extensions.size()); EXPECT_TRUE(base::ASCIIToUTF16("Extension 1") == suspicious_extensions[0]); - bubble.set_controller(controller.get()); controller->Show(&bubble); // Simulate showing the bubble. EXPECT_EQ(0U, controller->link_click_count()); EXPECT_EQ(1U, controller->dismiss_click_count()); @@ -494,16 +497,20 @@ ASSERT_EQ(2U, suspicious_extensions.size()); EXPECT_TRUE(base::ASCIIToUTF16("Extension 1") == suspicious_extensions[1]); EXPECT_TRUE(base::ASCIIToUTF16("Extension 2") == suspicious_extensions[0]); - bubble.set_controller(controller.get()); controller->Show(&bubble); // Simulate showing the bubble. EXPECT_EQ(1U, controller->link_click_count()); EXPECT_EQ(0U, controller->dismiss_click_count()); EXPECT_TRUE(controller->delegate()->HasBubbleInfoBeenAcknowledged(kId1)); } -// The feature this is meant to test is only enacted on Windows, but it should -// pass on all platforms. -TEST_F(ExtensionMessageBubbleTest, DevModeControllerTest) { +// The feature this is meant to test is only implemented on Windows. +#if defined(OS_WIN) +#define MAYBE_DevModeControllerTest DevModeControllerTest +#else +#define MAYBE_DevModeControllerTest DISABLED_DevModeControllerTest +#endif + +TEST_F(ExtensionMessageBubbleTest, MAYBE_DevModeControllerTest) { FeatureSwitch::ScopedOverride force_dev_mode_highlighting( FeatureSwitch::force_dev_mode_highlighting(), true); Init(); @@ -532,7 +539,6 @@ FakeExtensionMessageBubble bubble; bubble.set_action_on_show( FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_DISMISS_BUTTON); - bubble.set_controller(controller.get()); controller->Show(&bubble); EXPECT_EQ(0U, controller->link_click_count()); EXPECT_EQ(0U, controller->action_click_count()); @@ -550,7 +556,6 @@ EXPECT_TRUE(controller->ShouldShow()); dev_mode_extensions = controller->GetExtensionList(); EXPECT_EQ(2U, dev_mode_extensions.size()); - bubble.set_controller(controller.get()); controller->Show(&bubble); // Simulate showing the bubble. EXPECT_EQ(0U, controller->link_click_count()); EXPECT_EQ(1U, controller->action_click_count()); @@ -571,7 +576,6 @@ EXPECT_TRUE(controller->ShouldShow()); dev_mode_extensions = controller->GetExtensionList(); EXPECT_EQ(2U, dev_mode_extensions.size()); - bubble.set_controller(controller.get()); controller->Show(&bubble); // Simulate showing the bubble. EXPECT_EQ(1U, controller->link_click_count()); EXPECT_EQ(0U, controller->action_click_count()); @@ -639,7 +643,7 @@ profile(), static_cast<SettingsApiOverrideType>(i))); // The list will contain one enabled unpacked extension (ext 2). - EXPECT_TRUE(controller->ShouldShow()); + EXPECT_TRUE(controller->ShouldShow(kId2)); std::vector<base::string16> override_extensions = controller->GetExtensionList(); ASSERT_EQ(1U, override_extensions.size()); @@ -653,7 +657,6 @@ FakeExtensionMessageBubble bubble; bubble.set_action_on_show( FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_DISMISS_BUTTON); - bubble.set_controller(controller.get()); controller->Show(&bubble); EXPECT_EQ(0U, controller->link_click_count()); EXPECT_EQ(0U, controller->action_click_count()); @@ -675,7 +678,6 @@ FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_LINK); controller.reset(new TestSettingsApiBubbleController( profile(), static_cast<SettingsApiOverrideType>(i))); - bubble.set_controller(controller.get()); controller->Show(&bubble); EXPECT_EQ(1U, controller->link_click_count()); EXPECT_EQ(0U, controller->action_click_count()); @@ -696,10 +698,9 @@ FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_ACTION_BUTTON); controller.reset(new TestSettingsApiBubbleController( profile(), static_cast<SettingsApiOverrideType>(i))); - EXPECT_TRUE(controller->ShouldShow()); + EXPECT_TRUE(controller->ShouldShow(kId2)); override_extensions = controller->GetExtensionList(); EXPECT_EQ(1U, override_extensions.size()); - bubble.set_controller(controller.get()); controller->Show(&bubble); // Simulate showing the bubble. EXPECT_EQ(0U, controller->link_click_count()); EXPECT_EQ(1U, controller->action_click_count()); @@ -729,9 +730,14 @@ } } -// The feature this is meant to test is only enacted on Windows, but it should -// pass on all platforms. -TEST_F(ExtensionMessageBubbleTest, NtpOverriddenControllerTest) { +// The feature this is meant to test is only implemented on Windows. +#if defined(OS_WIN) +#define MAYBE_NtpOverriddenControllerTest NtpOverriddenControllerTest +#else +#define MAYBE_NtpOverriddenControllerTest DISABLED_NtpOverriddenControllerTest +#endif + +TEST_F(ExtensionMessageBubbleTest, MAYBE_NtpOverriddenControllerTest) { Init(); // Load two extensions overriding new tab page and one overriding something // unrelated (to check for interference). Extension 2 should still win @@ -759,7 +765,6 @@ bubble.set_action_on_show( FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_DISMISS_BUTTON); EXPECT_TRUE(controller->ShouldShow(kId2)); - bubble.set_controller(controller.get()); controller->Show(&bubble); EXPECT_EQ(0U, controller->link_click_count()); EXPECT_EQ(0U, controller->action_click_count()); @@ -781,7 +786,6 @@ FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_LINK); controller.reset(new TestNtpOverriddenBubbleController(profile())); EXPECT_TRUE(controller->ShouldShow(kId2)); - bubble.set_controller(controller.get()); controller->Show(&bubble); EXPECT_EQ(1U, controller->link_click_count()); EXPECT_EQ(0U, controller->action_click_count()); @@ -804,7 +808,6 @@ EXPECT_TRUE(controller->ShouldShow(kId2)); override_extensions = controller->GetExtensionList(); EXPECT_EQ(1U, override_extensions.size()); - bubble.set_controller(controller.get()); controller->Show(&bubble); // Simulate showing the bubble. EXPECT_EQ(0U, controller->link_click_count()); EXPECT_EQ(1U, controller->action_click_count()); @@ -892,7 +895,6 @@ FakeExtensionMessageBubble bubble; bubble.set_action_on_show( FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_DISMISS_BUTTON); - bubble.set_controller(controller.get()); controller->Show(&bubble); EXPECT_EQ(0U, controller->link_click_count()); EXPECT_EQ(0U, controller->action_click_count()); @@ -914,7 +916,6 @@ FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_LINK); controller.reset(new TestProxyOverriddenBubbleController(profile())); EXPECT_TRUE(controller->ShouldShow(kId2)); - bubble.set_controller(controller.get()); controller->Show(&bubble); EXPECT_EQ(1U, controller->link_click_count()); EXPECT_EQ(0U, controller->action_click_count()); @@ -937,7 +938,6 @@ EXPECT_TRUE(controller->ShouldShow(kId2)); override_extensions = controller->GetExtensionList(); EXPECT_EQ(1U, override_extensions.size()); - bubble.set_controller(controller.get()); controller->Show(&bubble); // Simulate showing the bubble. EXPECT_EQ(0U, controller->link_click_count()); EXPECT_EQ(1U, controller->action_click_count());
diff --git a/chrome/browser/extensions/extension_startup_browsertest.cc b/chrome/browser/extensions/extension_startup_browsertest.cc index d61a48d2..90acea6 100644 --- a/chrome/browser/extensions/extension_startup_browsertest.cc +++ b/chrome/browser/extensions/extension_startup_browsertest.cc
@@ -198,20 +198,17 @@ // extensions installed and see them run and do basic things. typedef ExtensionStartupTestBase ExtensionsStartupTest; -IN_PROC_BROWSER_TEST_F(ExtensionsStartupTest, Test) { +// Broken in official builds, http://crbug.com/474659 +IN_PROC_BROWSER_TEST_F(ExtensionsStartupTest, DISABLED_Test) { WaitForServicesToStart(num_expected_extensions_, true); TestInjection(true, true); } +// Broken in official builds, http://crbug.com/474659 // Sometimes times out on Mac. http://crbug.com/48151 -#if defined(OS_MACOSX) -#define MAYBE_NoFileAccess DISABLED_NoFileAccess -#else -#define MAYBE_NoFileAccess NoFileAccess -#endif // Tests that disallowing file access on an extension prevents it from injecting // script into a page with a file URL. -IN_PROC_BROWSER_TEST_F(ExtensionsStartupTest, MAYBE_NoFileAccess) { +IN_PROC_BROWSER_TEST_F(ExtensionsStartupTest, DISABLED_NoFileAccess) { WaitForServicesToStart(num_expected_extensions_, true); // Keep a separate list of extensions for which to disable file access, since
diff --git a/chrome/browser/extensions/external_component_loader.cc b/chrome/browser/extensions/external_component_loader.cc index d536187..4df086a6 100644 --- a/chrome/browser/extensions/external_component_loader.cc +++ b/chrome/browser/extensions/external_component_loader.cc
@@ -4,12 +4,14 @@ #include "chrome/browser/extensions/external_component_loader.h" +#include "base/command_line.h" #include "base/strings/string_number_conversions.h" #include "chrome/browser/bookmarks/enhanced_bookmarks_features.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/search/hotword_service.h" #include "chrome/browser/search/hotword_service_factory.h" #include "chrome/browser/signin/signin_manager_factory.h" +#include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension_constants.h" #include "components/signin/core/browser/signin_manager.h" #include "extensions/common/extension.h" @@ -79,6 +81,16 @@ } #endif + +#if defined(ENABLE_MEDIA_ROUTER) + if (switches::MediaRouterEnabled()) { + std::string media_router_extension_id( + extension_misc::kMediaRouterStableExtensionId); + prefs_->SetString(media_router_extension_id + ".external_update_url", + extension_urls::GetWebstoreUpdateUrl().spec()); + } +#endif // defined(ENABLE_MEDIA_ROUTER) + #if defined(ENABLE_APP_LIST) && defined(OS_CHROMEOS) std::string google_now_extension_id; if (GetGoogleNowExtensionId(&google_now_extension_id)) {
diff --git a/chrome/browser/extensions/ntp_overridden_bubble_controller.cc b/chrome/browser/extensions/ntp_overridden_bubble_controller.cc index 317b7bae..bec4ed3c 100644 --- a/chrome/browser/extensions/ntp_overridden_bubble_controller.cc +++ b/chrome/browser/extensions/ntp_overridden_bubble_controller.cc
@@ -47,7 +47,6 @@ base::string16 GetActionButtonLabel() const override; base::string16 GetDismissButtonLabel() const override; bool ShouldShowExtensionList() const override; - bool ShouldHighlightExtensions() const override; void RestrictToSingleExtension(const std::string& extension_id) override; void LogExtensionCount(size_t count) override; void LogAction(extensions::ExtensionMessageBubbleController::BubbleAction @@ -143,10 +142,6 @@ return false; } -bool NtpOverriddenBubbleDelegate::ShouldHighlightExtensions() const { - return false; -} - void NtpOverriddenBubbleDelegate::RestrictToSingleExtension( const std::string& extension_id) { extension_id_ = extension_id;
diff --git a/chrome/browser/extensions/proxy_overridden_bubble_controller.cc b/chrome/browser/extensions/proxy_overridden_bubble_controller.cc index d25204d..a3cde4c 100644 --- a/chrome/browser/extensions/proxy_overridden_bubble_controller.cc +++ b/chrome/browser/extensions/proxy_overridden_bubble_controller.cc
@@ -51,7 +51,6 @@ base::string16 GetActionButtonLabel() const override; base::string16 GetDismissButtonLabel() const override; bool ShouldShowExtensionList() const override; - bool ShouldHighlightExtensions() const override; void RestrictToSingleExtension(const std::string& extension_id) override; void LogExtensionCount(size_t count) override; void LogAction( @@ -162,10 +161,6 @@ return false; } -bool ProxyOverriddenBubbleDelegate::ShouldHighlightExtensions() const { - return true; -} - void ProxyOverriddenBubbleDelegate::RestrictToSingleExtension( const std::string& extension_id) { extension_id_ = extension_id;
diff --git a/chrome/browser/extensions/settings_api_bubble_controller.cc b/chrome/browser/extensions/settings_api_bubble_controller.cc index e90cf93..e89f42f 100644 --- a/chrome/browser/extensions/settings_api_bubble_controller.cc +++ b/chrome/browser/extensions/settings_api_bubble_controller.cc
@@ -54,7 +54,6 @@ base::string16 GetActionButtonLabel() const override; base::string16 GetDismissButtonLabel() const override; bool ShouldShowExtensionList() const override; - bool ShouldHighlightExtensions() const override; void LogExtensionCount(size_t count) override; void LogAction( ExtensionMessageBubbleController::BubbleAction action) override; @@ -245,10 +244,6 @@ return false; } -bool SettingsApiBubbleDelegate::ShouldHighlightExtensions() const { - return type_ == BUBBLE_TYPE_STARTUP_PAGES; -} - void SettingsApiBubbleDelegate::LogExtensionCount(size_t count) { } @@ -295,27 +290,11 @@ SettingsApiBubbleController::~SettingsApiBubbleController() {} -bool SettingsApiBubbleController::ShouldShow() { - const Extension* extension = nullptr; - switch (type_) { - case BUBBLE_TYPE_HOME_PAGE: - extension = GetExtensionOverridingHomepage(profile_); - break; - case BUBBLE_TYPE_SEARCH_ENGINE: - extension = GetExtensionOverridingSearchEngine(profile_); - break; - case BUBBLE_TYPE_STARTUP_PAGES: - extension = GetExtensionOverridingStartupPages(profile_); - break; - } - - if (!extension) +bool SettingsApiBubbleController::ShouldShow(const std::string& extension_id) { + if (delegate()->HasBubbleInfoBeenAcknowledged(extension_id)) return false; - if (delegate()->HasBubbleInfoBeenAcknowledged(extension->id())) - return false; - - if (!delegate()->ShouldIncludeExtension(extension->id())) + if (!delegate()->ShouldIncludeExtension(extension_id)) return false; // If the browser is showing the 'Chrome crashed' infobar, it won't be showing
diff --git a/chrome/browser/extensions/settings_api_bubble_controller.h b/chrome/browser/extensions/settings_api_bubble_controller.h index 42095330..df64077 100644 --- a/chrome/browser/extensions/settings_api_bubble_controller.h +++ b/chrome/browser/extensions/settings_api_bubble_controller.h
@@ -6,7 +6,6 @@ #define CHROME_BROWSER_EXTENSIONS_SETTINGS_API_BUBBLE_CONTROLLER_H_ #include <string> - #include "chrome/browser/extensions/extension_message_bubble_controller.h" #include "chrome/common/extensions/manifest_handlers/settings_overrides_handler.h" @@ -19,9 +18,9 @@ SettingsApiBubbleController(Profile* profile, SettingsApiOverrideType type); ~SettingsApiBubbleController() override; - // Returns true if we should show the bubble for the extension actively - // overriding the setting of |type_|. - bool ShouldShow(); + // Whether the controller knows that we should show the bubble for extension + // with |extension_id|. Returns true if so. + bool ShouldShow(const std::string& extension_id); // ExtensionMessageBubbleController: bool CloseOnDeactivate() override;
diff --git a/chrome/browser/extensions/suspicious_extension_bubble_controller.cc b/chrome/browser/extensions/suspicious_extension_bubble_controller.cc index 94d189f..da364b2 100644 --- a/chrome/browser/extensions/suspicious_extension_bubble_controller.cc +++ b/chrome/browser/extensions/suspicious_extension_bubble_controller.cc
@@ -53,7 +53,6 @@ base::string16 GetActionButtonLabel() const override; base::string16 GetDismissButtonLabel() const override; bool ShouldShowExtensionList() const override; - bool ShouldHighlightExtensions() const override; void LogExtensionCount(size_t count) override; void LogAction( ExtensionMessageBubbleController::BubbleAction action) override; @@ -127,14 +126,11 @@ return l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNSUPPORTED_DISABLED_BUTTON); } -bool SuspiciousExtensionBubbleDelegate::ShouldShowExtensionList() const { +bool +SuspiciousExtensionBubbleDelegate::ShouldShowExtensionList() const { return true; } -bool SuspiciousExtensionBubbleDelegate::ShouldHighlightExtensions() const { - return false; -} - void SuspiciousExtensionBubbleDelegate::LogExtensionCount( size_t count) { UMA_HISTOGRAM_COUNTS_100(
diff --git a/chrome/browser/favicon/DEPS b/chrome/browser/favicon/DEPS index 7bc0c6f..bd86119 100644 --- a/chrome/browser/favicon/DEPS +++ b/chrome/browser/favicon/DEPS
@@ -1,39 +1,14 @@ include_rules = [ - # Favicon is being made into a Browser Component, so we have these - # three basic rules followed by temporary exceptions. Please don't - # add to the list of exceptions! - "-chrome/browser", - "+chrome/browser/chrome_notification_types.h", - "+chrome/browser/common", - "+chrome/browser/favicon", - - # Permanently-allowed DEPS beyond the standard Browser - # Components-like DEPS above go here. - "+chrome/browser/profiles/incognito_helpers.h", - "+chrome/browser/search/search.h", - "+components/favicon/core", - "+net/base/registry_controlled_domains/registry_controlled_domain.h", - "+third_party/skia/include/core/SkBitmap.h", - - # TODO(caitkp): Bring this list to zero. + # Favicon is a layered component [1]. You will only find Chrome specific + # factories and helper in that directory, the meat of the components is + # located at //components/favicon. # - # Do not add to the list of temporarily-allowed dependencies below, - # and please do not introduce more #includes of these files. - "!chrome/browser/bookmarks/bookmark_model_factory.h", - "!chrome/browser/history/history_backend.h", - "!chrome/browser/history/history_service.h", - "!chrome/browser/history/history_service_factory.h", - "!chrome/browser/history/select_favicon_frames.h", - "!chrome/browser/profiles/profile.h", - "!chrome/browser/ui/webui/chrome_web_ui_controller_factory.h", - "!components/bookmarks/browser/bookmark_model.h", - # Do not add to the list of temporarily-allowed dependencies above, - # and please do not introduce more #includes of these files. + # [1]: http://www.chromium.org/developers/design-documents/layered-components-design + "+chrome/browser", ] specific_include_rules = { - # Browser tests, by definition, need access to the browser objects. - '.*_browsertest\.cc': [ - "+chrome/browser", + '.*test\.cc': [ + "+chrome/test", ] }
diff --git a/chrome/browser/favicon/OWNERS b/chrome/browser/favicon/OWNERS index f061d752..c888e8735 100644 --- a/chrome/browser/favicon/OWNERS +++ b/chrome/browser/favicon/OWNERS
@@ -3,7 +3,4 @@ stevenjb@chromium.org # Temporary owner, for refactoring changes only. -sdefresne@chromium.org - -# Temporary owner, for refactoring changes only. caitkp@chromium.org
diff --git a/chrome/browser/history/expire_history_backend_unittest.cc b/chrome/browser/history/expire_history_backend_unittest.cc index dc6dbdf..32a26d2 100644 --- a/chrome/browser/history/expire_history_backend_unittest.cc +++ b/chrome/browser/history/expire_history_backend_unittest.cc
@@ -463,8 +463,9 @@ EXPECT_TRUE(HasFavicon(favicon_id)); } -// DeleteURL should not delete starred urls. -TEST_F(ExpireHistoryTest, DontDeleteStarredURL) { +// DeleteURL should delete the history of starred urls, but the URL should +// remain starred and its favicon should remain too. +TEST_F(ExpireHistoryTest, DeleteStarredVisitedURL) { URLID url_ids[3]; Time visit_times[4]; AddExampleData(url_ids, visit_times); @@ -478,31 +479,44 @@ // Attempt to delete the url. expirer_.DeleteURL(url_row.url()); - // Because the url is starred, it shouldn't be deleted. + // Verify it no longer exists. GURL url = url_row.url(); - ASSERT_TRUE(main_db_->GetRowForURL(url, &url_row)); + ASSERT_FALSE(main_db_->GetRowForURL(url, &url_row)); + EnsureURLInfoGone(url_row, false); - // And the favicon should exist. + // Yet the favicon should exist. favicon_base::FaviconID favicon_id = - GetFavicon(url_row.url(), favicon_base::FAVICON); + GetFavicon(url, favicon_base::FAVICON); EXPECT_TRUE(HasFavicon(favicon_id)); - // And no visits. - VisitVector visits; - main_db_->GetVisitsForURL(url_row.id(), &visits); - ASSERT_EQ(0U, visits.size()); - // Should still have the thumbnail. // TODO(sky): fix this, see comment in HasThumbnail. // ASSERT_TRUE(HasThumbnail(url_row.id())); +} - // Unstar the URL and delete again. - history_client_.ClearAllBookmarks(); - ClearLastNotifications(); +// DeleteURL should not delete the favicon of bookmarked URLs. +TEST_F(ExpireHistoryTest, DeleteStarredUnvisitedURL) { + // Create a bookmark associated with a favicon. + const GURL url("http://www.google.com/starred"); + favicon_base::FaviconID favicon = + thumb_db_->AddFavicon(GURL("http://favicon/url1"), favicon_base::FAVICON); + thumb_db_->AddIconMapping(url, favicon); + StarURL(url); + + // Delete it. expirer_.DeleteURL(url); - // Now it should be completely deleted. - EnsureURLInfoGone(url_row, false); + // The favicon should exist. + favicon_base::FaviconID favicon_id = GetFavicon(url, favicon_base::FAVICON); + EXPECT_TRUE(HasFavicon(favicon_id)); + + // Unstar the URL and try again to delete it. + history_client_.ClearAllBookmarks(); + expirer_.DeleteURL(url); + + // The favicon should be gone. + favicon_id = GetFavicon(url, favicon_base::FAVICON); + EXPECT_FALSE(HasFavicon(favicon_id)); } // Deletes multiple URLs at once. The favicon for the third one but @@ -533,8 +547,7 @@ // Delete the URLs and their dependencies. expirer_.DeleteURLs(urls); - // First one should still be around (since it was starred). - ASSERT_TRUE(main_db_->GetRowForURL(rows[0].url(), &rows[0])); + EnsureURLInfoGone(rows[0], false); EnsureURLInfoGone(rows[1], false); EnsureURLInfoGone(rows[2], false); EXPECT_TRUE(HasFavicon(favicon_ids[0]));
diff --git a/chrome/browser/history/history_backend_unittest.cc b/chrome/browser/history/history_backend_unittest.cc index c6de4d0..c578922 100644 --- a/chrome/browser/history/history_backend_unittest.cc +++ b/chrome/browser/history/history_backend_unittest.cc
@@ -796,13 +796,9 @@ history_client_.AddBookmark(row1.url()); history_client_.AddBookmark(row2.url()); - // Delete url 2. Because url 2 is starred this won't delete the URL, only - // the visits. + // Delete url 2. backend_->expirer_.DeleteURL(row2.url()); - - // Make sure url 2 is still valid, but has no visits. - URLRow tmp_url_row; - EXPECT_EQ(row2_id, backend_->db_->GetRowForURL(row2.url(), NULL)); + EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), NULL)); VisitVector visits; backend_->db_->GetVisitsForURL(row2_id, &visits); EXPECT_EQ(0U, visits.size()); @@ -820,8 +816,8 @@ unstarred_urls.insert(row2.url()); backend_->URLsNoLongerBookmarked(unstarred_urls); - // The URL should no longer exist. - EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &tmp_url_row)); + // The URL should still not exist. + EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), NULL)); // And the favicon should be deleted. EXPECT_EQ(0, backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
diff --git a/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc b/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc index 2faefc5b..db3c0812 100644 --- a/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc +++ b/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc
@@ -582,6 +582,35 @@ validate_media_files()))); } +void DeviceMediaAsyncFileUtil::AddWatcher( + const storage::FileSystemURL& url, + bool recursive, + const storage::WatcherManager::StatusCallback& callback, + const storage::WatcherManager::NotificationCallback& + notification_callback) { + MTPDeviceAsyncDelegate* const delegate = GetMTPDeviceDelegate(url); + if (!delegate) { + callback.Run(base::File::FILE_ERROR_FAILED); + return; + } + + delegate->AddWatcher(url.origin(), url.path(), recursive, callback, + notification_callback); +} + +void DeviceMediaAsyncFileUtil::RemoveWatcher( + const storage::FileSystemURL& url, + const bool recursive, + const storage::WatcherManager::StatusCallback& callback) { + MTPDeviceAsyncDelegate* const delegate = GetMTPDeviceDelegate(url); + if (!delegate) { + callback.Run(base::File::FILE_ERROR_FAILED); + return; + } + + delegate->RemoveWatcher(url.origin(), url.path(), recursive, callback); +} + DeviceMediaAsyncFileUtil::DeviceMediaAsyncFileUtil( const base::FilePath& profile_path, MediaFileValidationType validation_type)
diff --git a/chrome/browser/media_galleries/fileapi/device_media_async_file_util.h b/chrome/browser/media_galleries/fileapi/device_media_async_file_util.h index 5683a73..6b32d849 100644 --- a/chrome/browser/media_galleries/fileapi/device_media_async_file_util.h +++ b/chrome/browser/media_galleries/fileapi/device_media_async_file_util.h
@@ -12,6 +12,7 @@ #include "base/memory/weak_ptr.h" #include "storage/browser/blob/shareable_file_reference.h" #include "storage/browser/fileapi/async_file_util.h" +#include "storage/browser/fileapi/watcher_manager.h" namespace storage { class FileSystemOperationContext; @@ -108,6 +109,18 @@ const base::Time& expected_modification_time, storage::FileSystemContext* context); + // Adds watcher to |url|. + void AddWatcher(const storage::FileSystemURL& url, + bool recursive, + const storage::WatcherManager::StatusCallback& callback, + const storage::WatcherManager::NotificationCallback& + notification_callback); + + // Removes watcher of |url|. + void RemoveWatcher(const storage::FileSystemURL& url, + const bool recursive, + const storage::WatcherManager::StatusCallback& callback); + private: class MediaPathFilterWrapper;
diff --git a/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h b/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h index b25eef9..2ebfa939e 100644 --- a/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h +++ b/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h
@@ -9,6 +9,8 @@ #include "base/files/file.h" #include "base/memory/ref_counted.h" #include "storage/browser/fileapi/async_file_util.h" +#include "storage/browser/fileapi/watcher_manager.h" +#include "url/gurl.h" namespace base { class FilePath; @@ -176,6 +178,22 @@ const DeleteDirectorySuccessCallback& success_callback, const ErrorCallback& error_callback) = 0; + // Adds watcher to |file_path| as |origin|. + virtual void AddWatcher( + const GURL& origin, + const base::FilePath& file_path, + const bool recursive, + const storage::WatcherManager::StatusCallback& callback, + const storage::WatcherManager::NotificationCallback& + notification_callback) = 0; + + // Removes watcher from |file_path| of |origin|. + virtual void RemoveWatcher( + const GURL& origin, + const base::FilePath& file_path, + const bool recursive, + const storage::WatcherManager::StatusCallback& callback) = 0; + // Called when the // (1) Browser application is in shutdown mode (or) // (2) Last extension using this MTP device is destroyed (or)
diff --git a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc index b6f8a346..5eadd21b 100644 --- a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc +++ b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc
@@ -754,6 +754,76 @@ FROM_HERE, closure)); } +void MTPDeviceDelegateImplLinux::AddWatcher( + const GURL& origin, + const base::FilePath& file_path, + const bool recursive, + const storage::WatcherManager::StatusCallback& callback, + const storage::WatcherManager::NotificationCallback& + notification_callback) { + if (recursive) { + callback.Run(base::File::FILE_ERROR_INVALID_OPERATION); + return; + } + + // TODO(yawano) Checks existence of |file_path|. + const auto it = subscribers_.find(file_path); + if (it != subscribers_.end()) { + // Adds to existing origin callback map. + if (ContainsKey(it->second, origin)) { + callback.Run(base::File::FILE_ERROR_EXISTS); + return; + } + + it->second.insert(std::make_pair(origin, notification_callback)); + } else { + // Creates new origin callback map. + OriginNotificationCallbackMap callback_map; + callback_map.insert(std::make_pair(origin, notification_callback)); + subscribers_.insert(std::make_pair(file_path, callback_map)); + } + + callback.Run(base::File::FILE_OK); +} + +void MTPDeviceDelegateImplLinux::RemoveWatcher( + const GURL& origin, + const base::FilePath& file_path, + const bool recursive, + const storage::WatcherManager::StatusCallback& callback) { + if (recursive) { + callback.Run(base::File::FILE_ERROR_INVALID_OPERATION); + return; + } + + const auto it = subscribers_.find(file_path); + if (it == subscribers_.end()) { + callback.Run(base::File::FILE_ERROR_NOT_FOUND); + return; + } + + if (it->second.erase(origin) == 0) { + callback.Run(base::File::FILE_ERROR_NOT_FOUND); + return; + } + + if (it->second.empty()) + subscribers_.erase(it); + + callback.Run(base::File::FILE_OK); +} + +void MTPDeviceDelegateImplLinux::NotifyFileChange( + const base::FilePath& file_path, + const storage::WatcherManager::ChangeType change_type) { + const auto it = subscribers_.find(file_path); + if (it != subscribers_.end()) { + for (const auto& origin_callback : it->second) { + origin_callback.second.Run(change_type); + } + } +} + void MTPDeviceDelegateImplLinux::CancelPendingTasksAndDeleteDelegate() { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); // To cancel all the pending tasks, destroy the MTPDeviceTaskHelper object. @@ -1343,9 +1413,9 @@ } const MTPDeviceTaskHelper::CreateDirectorySuccessCallback - success_callback_wrapper = - base::Bind(&MTPDeviceDelegateImplLinux::OnDidCreateSingleDirectory, - weak_ptr_factory_.GetWeakPtr(), success_callback); + success_callback_wrapper = base::Bind( + &MTPDeviceDelegateImplLinux::OnDidCreateSingleDirectory, + weak_ptr_factory_.GetWeakPtr(), directory_path, success_callback); const MTPDeviceTaskHelper::ErrorCallback error_callback_wrapper = base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError, weak_ptr_factory_.GetWeakPtr(), error_callback, parent_id); @@ -1448,10 +1518,13 @@ } void MTPDeviceDelegateImplLinux::OnDidCreateSingleDirectory( + const base::FilePath& directory_path, const CreateDirectorySuccessCallback& success_callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); success_callback.Run(); + NotifyFileChange(directory_path.DirName(), + storage::WatcherManager::ChangeType::CHANGED); PendingRequestDone(); }
diff --git a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h index b11eef3..3242740 100644 --- a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h +++ b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h
@@ -124,6 +124,17 @@ void DeleteDirectory(const base::FilePath& file_path, const DeleteDirectorySuccessCallback& success_callback, const ErrorCallback& error_callback) override; + void AddWatcher(const GURL& origin, + const base::FilePath& file_path, + const bool recursive, + const storage::WatcherManager::StatusCallback& callback, + const storage::WatcherManager::NotificationCallback& + notification_callback) override; + void RemoveWatcher( + const GURL& origin, + const base::FilePath& file_path, + const bool recursive, + const storage::WatcherManager::StatusCallback& callback) override; void CancelPendingTasksAndDeleteDelegate() override; // The internal methods correspond to the similarly named methods above. @@ -206,6 +217,10 @@ const DeleteObjectSuccessCallback& success_callback, const ErrorCallback& error_callback); + // Notifies |chage_type| of |file_path| to watchers. + void NotifyFileChange(const base::FilePath& file_path, + const storage::WatcherManager::ChangeType change_type); + // Ensures the device is initialized for communication. // If the device is already initialized, call RunTask(). // @@ -303,6 +318,7 @@ // Called when CreateSignleDirectory() succeeds. void OnDidCreateSingleDirectory( + const base::FilePath& directory_path, const CreateDirectorySuccessCallback& success_callback); // Called when parent directory |created_directory| is created as part of @@ -458,6 +474,12 @@ // Mode for opening storage. const bool read_only_; + // Maps for holding notification callbacks. + typedef std::map<GURL, storage::WatcherManager::NotificationCallback> + OriginNotificationCallbackMap; + typedef std::map<base::FilePath, OriginNotificationCallbackMap> Subscribers; + Subscribers subscribers_; + // A list of pending tasks that needs to be run when the device is // initialized or when the current task in progress is complete. std::deque<PendingTaskInfo> pending_tasks_;
diff --git a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h index d01874c7..c92da81 100644 --- a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h +++ b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h
@@ -85,6 +85,17 @@ void DeleteDirectory(const base::FilePath& file_path, const DeleteDirectorySuccessCallback& success_callback, const ErrorCallback& error_callback) override; + void AddWatcher(const GURL& origin, + const base::FilePath& file_path, + const bool recursive, + const storage::WatcherManager::StatusCallback& callback, + const storage::WatcherManager::NotificationCallback& + notification_callback) override; + void RemoveWatcher( + const GURL& origin, + const base::FilePath& file_path, + const bool recursive, + const storage::WatcherManager::StatusCallback& callback) override; void CancelPendingTasksAndDeleteDelegate() override; // Forward delegates for ImageCaptureDeviceListener. These are
diff --git a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm index 56b39ae..89e5108 100644 --- a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm +++ b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
@@ -263,6 +263,26 @@ NOTREACHED(); } +void MTPDeviceDelegateImplMac::AddWatcher( + const GURL& origin, + const base::FilePath& file_path, + const bool recursive, + const storage::WatcherManager::StatusCallback& callback, + const storage::WatcherManager::NotificationCallback& + notification_callback) { + NOTIMPLEMENTED(); + callback.Run(base::File::FILE_ERROR_INVALID_OPERATION); +} + +void MTPDeviceDelegateImplMac::RemoveWatcher( + const GURL& origin, + const base::FilePath& file_path, + const bool recursive, + const storage::WatcherManager::StatusCallback& callback) { + NOTIMPLEMENTED(); + callback.Run(base::File::FILE_ERROR_INVALID_OPERATION); +} + void MTPDeviceDelegateImplMac::CancelPendingTasksAndDeleteDelegate() { content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, base::Bind(&MTPDeviceDelegateImplMac::CancelAndDelete,
diff --git a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc index 8028cc5..fe563d6 100644 --- a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc +++ b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc
@@ -515,6 +515,26 @@ NOTREACHED(); } +void MTPDeviceDelegateImplWin::AddWatcher( + const GURL& origin, + const base::FilePath& file_path, + const bool recursive, + const storage::WatcherManager::StatusCallback& callback, + const storage::WatcherManager::NotificationCallback& + notification_callback) { + NOTIMPLEMENTED(); + callback.Run(base::File::FILE_ERROR_INVALID_OPERATION); +} + +void MTPDeviceDelegateImplWin::RemoveWatcher( + const GURL& origin, + const base::FilePath& file_path, + const bool recursive, + const storage::WatcherManager::StatusCallback& callback) { + NOTIMPLEMENTED(); + callback.Run(base::File::FILE_ERROR_INVALID_OPERATION); +} + void MTPDeviceDelegateImplWin::CancelPendingTasksAndDeleteDelegate() { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); PortableDeviceMapService::GetInstance()->MarkPortableDeviceForDeletion(
diff --git a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h index c90741d..11f3205 100644 --- a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h +++ b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h
@@ -140,6 +140,17 @@ void DeleteDirectory(const base::FilePath& file_path, const DeleteDirectorySuccessCallback& success_callback, const ErrorCallback& error_callback) override; + void AddWatcher(const GURL& origin, + const base::FilePath& file_path, + const bool recursive, + const storage::WatcherManager::StatusCallback& callback, + const storage::WatcherManager::NotificationCallback& + notification_callback) override; + void RemoveWatcher( + const GURL& origin, + const base::FilePath& file_path, + const bool recursive, + const storage::WatcherManager::StatusCallback& callback) override; virtual void CancelPendingTasksAndDeleteDelegate() override; // Ensures the device is initialized for communication by doing a
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 e6e8ae21..66cbc15 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
@@ -60,7 +60,7 @@ data_reduction_proxy_ui_service( new data_reduction_proxy::ContentDataReductionProxyDebugUIService( base::Bind(&data_reduction_proxy::DataReductionProxyConfigurator:: - GetProxyConfigOnIOThread, + GetProxyConfig, base::Unretained( data_reduction_proxy_io_data->configurator())), ui_task_runner, io_task_runner,
diff --git a/chrome/browser/password_manager/password_store_factory.cc b/chrome/browser/password_manager/password_store_factory.cc index fba3d006..78b24257 100644 --- a/chrome/browser/password_manager/password_store_factory.cc +++ b/chrome/browser/password_manager/password_store_factory.cc
@@ -13,6 +13,8 @@ #include "chrome/browser/profiles/incognito_helpers.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sync/glue/sync_start_util.h" +#include "chrome/browser/sync/profile_sync_service.h" +#include "chrome/browser/sync/profile_sync_service_factory.h" #include "chrome/browser/webdata/web_data_service_factory.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_switches.h" @@ -81,6 +83,49 @@ base::TimeDelta::FromSeconds(40)); } +base::FilePath GetAffiliationDatabasePath(Profile* profile) { + DCHECK(profile); + return profile->GetPath().Append(chrome::kAffiliationDatabaseFileName); +} + +bool ShouldAffiliationBasedMatchingBeActive(Profile* profile) { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (!password_manager::IsAffiliationBasedMatchingEnabled(*command_line)) + return false; + + DCHECK(profile); + ProfileSyncService* profile_sync_service = + ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile); + return profile_sync_service && + profile_sync_service->IsSyncEnabledAndLoggedIn() && + profile_sync_service->SyncActive() && + profile_sync_service->GetPreferredDataTypes().Has(syncer::PASSWORDS) && + !profile_sync_service->IsUsingSecondaryPassphrase(); +} + +void ActivateAffiliationBasedMatching(PasswordStore* password_store, + Profile* profile) { + DCHECK(password_store); + DCHECK(profile); + + // The PasswordStore is so far the only consumer of the AffiliationService, + // therefore the service is owned by the AffiliatedMatchHelper, which in + // turn is owned by the PasswordStore. + // TODO(engedy): Double-check which request context we want. + scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner( + content::BrowserThread::GetMessageLoopProxyForThread( + content::BrowserThread::DB)); + scoped_ptr<password_manager::AffiliationService> affiliation_service( + new password_manager::AffiliationService(db_thread_runner)); + affiliation_service->Initialize(profile->GetRequestContext(), + GetAffiliationDatabasePath(profile)); + scoped_ptr<password_manager::AffiliatedMatchHelper> affiliated_match_helper( + new password_manager::AffiliatedMatchHelper(password_store, + affiliation_service.Pass())); + affiliated_match_helper->Initialize(); + password_store->SetAffiliatedMatchHelper(affiliated_match_helper.Pass()); +} + } // namespace @@ -121,6 +166,24 @@ return Singleton<PasswordStoreFactory>::get(); } +// static +void PasswordStoreFactory::OnPasswordsSyncedStatePotentiallyChanged( + Profile* profile) { + scoped_refptr<PasswordStore> password_store = + GetForProfile(profile, ServiceAccessType::EXPLICIT_ACCESS); + if (!password_store) + return; + + if (ShouldAffiliationBasedMatchingBeActive(profile) && + !password_store->HasAffiliatedMatchHelper()) { + ActivateAffiliationBasedMatching(password_store.get(), profile); + } else if (!ShouldAffiliationBasedMatchingBeActive(profile) && + password_store->HasAffiliatedMatchHelper()) { + password_store->SetAffiliatedMatchHelper( + make_scoped_ptr<password_manager::AffiliatedMatchHelper>(nullptr)); + } +} + PasswordStoreFactory::PasswordStoreFactory() : BrowserContextKeyedServiceFactory( "PasswordStore", @@ -277,24 +340,6 @@ return nullptr; } - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (password_manager::IsAffiliationBasedMatchingEnabled(*command_line)) { - // The PasswordStore is so far the only consumer of the AffiliationService, - // therefore the service is owned by the AffiliatedMatchHelper, which in - // turn is owned by the PasswordStore. - // TODO(engedy): Double-check which request context we want. - scoped_ptr<password_manager::AffiliationService> affiliation_service( - new password_manager::AffiliationService(db_thread_runner)); - affiliation_service->Initialize( - profile->GetRequestContext(), - profile->GetPath().Append(chrome::kAffiliationDatabaseFileName)); - scoped_ptr<password_manager::AffiliatedMatchHelper> affiliated_match_helper( - new password_manager::AffiliatedMatchHelper( - ps.get(), affiliation_service.Pass())); - affiliated_match_helper->Initialize(); - ps->SetAffiliatedMatchHelper(affiliated_match_helper.Pass()); - } - return new PasswordStoreService(ps); }
diff --git a/chrome/browser/password_manager/password_store_factory.h b/chrome/browser/password_manager/password_store_factory.h index d11d2b8..25bd747 100644 --- a/chrome/browser/password_manager/password_store_factory.h +++ b/chrome/browser/password_manager/password_store_factory.h
@@ -58,6 +58,10 @@ static PasswordStoreFactory* GetInstance(); + // Called by the PasswordDataTypeController whenever there is a possibility + // that syncing passwords has just started or ended for |profile|. + static void OnPasswordsSyncedStatePotentiallyChanged(Profile* profile); + private: friend struct DefaultSingletonTraits<PasswordStoreFactory>;
diff --git a/chrome/browser/profiles/profile_browsertest.cc b/chrome/browser/profiles/profile_browsertest.cc index b502385..46623e7 100644 --- a/chrome/browser/profiles/profile_browsertest.cc +++ b/chrome/browser/profiles/profile_browsertest.cc
@@ -320,7 +320,7 @@ // The EndSession IO synchronization is only critical on Windows, but also // happens under the USE_X11 define. See BrowserProcessImpl::EndSession. -#if defined(USE_X11) || defined(OS_WIN) +#if defined(USE_X11) || defined(OS_WIN) || defined(USE_OZONE) namespace { @@ -408,4 +408,4 @@ ASSERT_TRUE(succeeded) << "profile->EndSession() timed out too often."; } -#endif // defined(USE_X11) || defined(OS_WIN) +#endif // defined(USE_X11) || defined(OS_WIN) || defined(USE_OZONE)
diff --git a/chrome/browser/push_messaging/push_messaging_browsertest.cc b/chrome/browser/push_messaging/push_messaging_browsertest.cc index 397d05b..9a1b15ca 100644 --- a/chrome/browser/push_messaging/push_messaging_browsertest.cc +++ b/chrome/browser/push_messaging/push_messaging_browsertest.cc
@@ -116,19 +116,6 @@ std::string app_id_; }; -// The Push API depends on Web Notifications, which is only available on Android -// Jelly Bean and later. -bool IsPushSupported() { -#if defined(OS_ANDROID) - if (base::android::BuildInfo::GetInstance()->sdk_int() < - base::android::SDK_VERSION_JELLY_BEAN) { - DVLOG(0) << "The Push API is only supported in Android 4.1 and later."; - return false; - } -#endif - return true; -} - } // namespace class PushMessagingBrowserTest : public InProcessBrowserTest { @@ -250,9 +237,6 @@ IN_PROC_BROWSER_TEST_F(PushMessagingBadManifestBrowserTest, RegisterFailsNotVisibleMessages) { - if (!IsPushSupported()) - return; - std::string script_result; ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result)); @@ -289,9 +273,6 @@ IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, RegisterSuccessNotificationsGranted) { - if (!IsPushSupported()) - return; - TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); PushMessagingApplicationId app_id = GetServiceWorkerAppId(0LL); @@ -301,9 +282,6 @@ IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, RegisterSuccessNotificationsPrompt) { - if (!IsPushSupported()) - return; - std::string script_result; ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result)); @@ -320,9 +298,6 @@ IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, RegisterFailureNotificationsBlocked) { - if (!IsPushSupported()) - return; - std::string script_result; ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result)); @@ -338,9 +313,6 @@ } IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, RegisterFailureNoManifest) { - if (!IsPushSupported()) - return; - std::string script_result; ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result)); @@ -361,9 +333,6 @@ // TODO(johnme): Test registering from a worker - see https://crbug.com/437298. IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, RegisterPersisted) { - if (!IsPushSupported()) - return; - std::string script_result; // First, test that Service Worker registration IDs are assigned in order of @@ -418,9 +387,6 @@ } IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PushEventSuccess) { - if (!IsPushSupported()) - return; - std::string script_result; TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); @@ -446,9 +412,6 @@ } IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PushEventNoServiceWorker) { - if (!IsPushSupported()) - return; - std::string script_result; TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); @@ -491,9 +454,6 @@ #if defined(ENABLE_NOTIFICATIONS) IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PushEventEnforcesUserVisibleNotification) { - if (!IsPushSupported()) - return; - std::string script_result; TryToRegisterSuccessfully("1-0" /* expected_push_registration_id */); @@ -590,9 +550,6 @@ IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PushEventNotificationWithoutEventWaitUntil) { - if (!IsPushSupported()) - return; - std::string script_result; content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); @@ -636,9 +593,6 @@ #endif IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, HasPermissionSaysDefault) { - if (!IsPushSupported()) - return; - std::string script_result; ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result)); @@ -649,9 +603,6 @@ } IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, HasPermissionSaysGranted) { - if (!IsPushSupported()) - return; - std::string script_result; ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result)); @@ -669,9 +620,6 @@ } IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, HasPermissionSaysDenied) { - if (!IsPushSupported()) - return; - std::string script_result; ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result)); @@ -690,9 +638,6 @@ } IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, UnregisterSuccess) { - if (!IsPushSupported()) - return; - std::string script_result; EXPECT_TRUE(RunScript("registerServiceWorker()", &script_result)); @@ -734,19 +679,6 @@ EXPECT_EQ("unregister result: false", script_result); } -#if defined(OS_ANDROID) -IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PushUnavailableOnAndroidICS) { - // This test should only run on Android ICS to confirm that the Push API - // is not available on that version of Android. - if (IsPushSupported()) - return; - - std::string script_result; - ASSERT_TRUE(RunScript("window.PushManager", &script_result)); - EXPECT_EQ("undefined", script_result); -} -#endif - IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, GlobalResetPushPermissionUnregisters) { std::string script_result;
diff --git a/chrome/browser/resources/bookmark_manager/js/main.js b/chrome/browser/resources/bookmark_manager/js/main.js index efbac59..acfc3d7d 100644 --- a/chrome/browser/resources/bookmark_manager/js/main.js +++ b/chrome/browser/resources/bookmark_manager/js/main.js
@@ -1029,13 +1029,13 @@ performGlobalUndo = null; // This can't be undone, so disable global undo. var parentId = computeParentFolderForNewItem(); - var selectedItem = bmm.list.selectedItem; + var selectedItems = bmm.list.selectedItems; var newIndex; // Callback is called after tree and list data model updated. function createFolder(callback) { - if (selectedItem && document.activeElement != bmm.tree && - !bmm.isFolder(selectedItem) && selectedItem.id != 'new') { - newIndex = bmm.list.dataModel.indexOf(selectedItem) + 1; + if (selectedItems.length == 1 && document.activeElement != bmm.tree && + !bmm.isFolder(selectedItems[0]) && selectedItems[0].id != 'new') { + newIndex = bmm.list.dataModel.indexOf(selectedItems[0]) + 1; } chrome.bookmarks.create({ title: loadTimeData.getString('new_folder_name'), @@ -1086,12 +1086,12 @@ */ function addPage() { var parentId = computeParentFolderForNewItem(); - var selectedItem = bmm.list.selectedItem; + var selectedItems = bmm.list.selectedItems; var newIndex; function editNewBookmark() { - if (selectedItem && document.activeElement != bmm.tree && - !bmm.isFolder(selectedItem)) { - newIndex = bmm.list.dataModel.indexOf(selectedItem) + 1; + if (selectedItems.length == 1 && document.activeElement != bmm.tree && + !bmm.isFolder(selectedItems[0])) { + newIndex = bmm.list.dataModel.indexOf(selectedItems[0]) + 1; } var fakeNode = {
diff --git a/chrome/browser/resources/chromeos/input_method/google_input_tools_manifest.json b/chrome/browser/resources/chromeos/input_method/google_input_tools_manifest.json index cf52fa28a..d8595ed 100644 --- a/chrome/browser/resources/chromeos/input_method/google_input_tools_manifest.json +++ b/chrome/browser/resources/chromeos/input_method/google_input_tools_manifest.json
@@ -148,7 +148,7 @@ "name": "__MSG_inputmethod_zhuyin__", "type": "ime", "id": "zh-hant-t-i0-und", - "indicator": "\u9177", + "indicator": "\u6CE8", "description": "Zhuyin", "language": [ "zh-TW",
diff --git a/chrome/browser/resources/chromeos/login/custom_elements.html b/chrome/browser/resources/chromeos/login/custom_elements.html index 3cd18cd..c043cd5 100644 --- a/chrome/browser/resources/chromeos/login/custom_elements.html +++ b/chrome/browser/resources/chromeos/login/custom_elements.html
@@ -4,5 +4,6 @@ <include src="controller-pairing-screen.html"> <include src="host-pairing-screen.html"> <include src="throbber_notice.html"> +<include src="notification_card.html"> <script src="chrome://oobe/custom_elements.js"></script>
diff --git a/chrome/browser/resources/chromeos/login/custom_elements.js b/chrome/browser/resources/chromeos/login/custom_elements.js index 587b93f..b5f32a0 100644 --- a/chrome/browser/resources/chromeos/login/custom_elements.js +++ b/chrome/browser/resources/chromeos/login/custom_elements.js
@@ -7,3 +7,4 @@ <include src="indeterminate-progress.js"> <include src="controller-pairing-screen.js"> <include src="host-pairing-screen.js"> +<include src="notification_card.js">
diff --git a/chrome/browser/resources/chromeos/login/gaia_whiteist_error.js b/chrome/browser/resources/chromeos/login/gaia_whiteist_error.js deleted file mode 100644 index eed9092..0000000 --- a/chrome/browser/resources/chromeos/login/gaia_whiteist_error.js +++ /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. - -Polymer('gaia-whitelist-error', (function() { - // The help topic regarding user not being in the whitelist. - /** @const */ var HELP_CANT_ACCESS_ACCOUNT = 188036; - - return { - enterpriseManaged: false, - - onLearnMoreClicked: function() { - chrome.send('launchHelpApp', [HELP_CANT_ACCESS_ACCOUNT]); - }, - - tryAgainButtonClicked: function() { - $('gaia-signin').showWhitelistCheckFailedError(false); - } - }; -})());
diff --git a/chrome/browser/resources/chromeos/login/gaia_whitelist_error.html b/chrome/browser/resources/chromeos/login/gaia_whitelist_error.html deleted file mode 100644 index b8c2a3cf..0000000 --- a/chrome/browser/resources/chromeos/login/gaia_whitelist_error.html +++ /dev/null
@@ -1,72 +0,0 @@ -<link rel="import" href="chrome://resources/polymer/polymer/polymer.html"> -<link rel="import" href="chrome://resources/polymer/paper-button/paper-button.html"> -<link rel="import" href="chrome://resources/polymer/core-icons/core-icons.html"> - -<polymer-element name="gaia-whitelist-error" attributes="errorMsg - enterpriseErrorMsg tryAgainBtn learnMoreBtn"> - <template> - <style> - #container { - padding: 40px; - } - - #icon-container { - margin-bottom: 14px; - } - - core-icon { - color: #fbc02d; - height: 28px; - width: 28px; - } - - #text-container { - color: grey; - line-height: 130%; - text-align: center; - width: 240px; - } - - #controls-container { - width: 100%; - } - - .learn-more-button { - color: rgb(66, 133, 244); - text-transform: none; - } - - .try-again-button { - background-color: rgb(66, 133, 244); - color: rgb(255, 255, 255); - width: 126px; - } - </style> - <div id="container" vertical layout center fit> - <div flex layout center-justified vertical> - <div id="icon-container" vertical layout center> - <core-icon icon="warning"></core-icon> - </div> - <div id="text-container"> - <div id="error-msg" hidden?="{{enterpriseManaged}}"> - {{errorMsg}} - </div> - <div id="enterprise-error-msg" hidden?="{{!enterpriseManaged}}"> - {{enterpriseErrorMsg}} - </div> - </div> - </div> - <div id="controls-container" horizontal layout justified - center> - <paper-button class="learn-more-button" - on-tap={{onLearnMoreClicked}}> - {{learnMoreBtn}} - </paper-button> - <paper-button class="try-again-button" raised - on-tap="{{tryAgainButtonClicked}}"> - {{tryAgainBtn}} - </paper-button> - </div> - </div> - </template> -</polymer-element> \ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/login/login.html b/chrome/browser/resources/chromeos/login/login.html index fa1e864..d51906c 100644 --- a/chrome/browser/resources/chromeos/login/login.html +++ b/chrome/browser/resources/chromeos/login/login.html
@@ -9,7 +9,7 @@ <title i18n-content="title"></title> <include src="login_resources.html"> <include src="throbber_notice.html"> -<include src="gaia_whitelist_error.html"> +<include src="notification_card.html"> <script src="chrome://oobe/login.js"></script> <script src="chrome://oobe/gaia_auth_host.js"></script> </head>
diff --git a/chrome/browser/resources/chromeos/login/login.js b/chrome/browser/resources/chromeos/login/login.js index 7f9ac0a0..ef3e6f0 100644 --- a/chrome/browser/resources/chromeos/login/login.js +++ b/chrome/browser/resources/chromeos/login/login.js
@@ -7,7 +7,7 @@ */ <include src="login_common.js"> -<include src="gaia_whiteist_error.js"> +<include src="notification_card.js"> cr.define('cr.ui.Oobe', function() { return {
diff --git a/chrome/browser/resources/chromeos/login/notification_card.css b/chrome/browser/resources/chromeos/login/notification_card.css new file mode 100644 index 0000000..7a728f3 --- /dev/null +++ b/chrome/browser/resources/chromeos/login/notification_card.css
@@ -0,0 +1,50 @@ +/* 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. + */ + +#container { + padding: 40px; +} + +#icon-container { + margin-bottom: 14px; +} + +/* ':host' and '[icon]' are needed to increase selector's specificity. */ +:host core-icon[icon] { + height: 28px; + width: 28px; +} + +core-icon[icon=warning] { + color: rgb(251, 192, 45); +} + +core-icon[icon=done] { + color: rgb(15, 157, 88); +} + +#heading { + font-size: 20px; + margin-bottom: 14px; +} + +#text-container { + color: grey; + line-height: 130%; + max-width: 240px; + text-align: center; +} + +paper-button { + background-color: rgb(66, 133, 244); + color: rgb(255, 255, 255); + min-width: 126px; +} + +a { + color: rgb(66, 133, 244); + text-decoration: none; +} +
diff --git a/chrome/browser/resources/chromeos/login/notification_card.html b/chrome/browser/resources/chromeos/login/notification_card.html new file mode 100644 index 0000000..34a4a328 --- /dev/null +++ b/chrome/browser/resources/chromeos/login/notification_card.html
@@ -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. --> + +<link rel="import" href="chrome://resources/polymer/polymer/polymer.html"> +<link rel="import" href="chrome://resources/polymer/paper-button/paper-button.html"> +<link rel="import" href="chrome://resources/polymer/core-icons/core-icons.html"> + +<!-- + A simple notification card with a button, link (optional) and icon (optional). + Example: + <notification-card buttonLabel="OK" linkLabel="What?" heading="Hello!" + type="success"> + Great success! + </notification-card> + + Atributes: + 'buttonLabel' - label displayed on the button. + 'linkLabel' - text of the link. If empty or not set, the link is hidden. + 'heading' - heading. Can be omitted. + 'type' - icon type. Can be either 'success' or 'fail'. If not set, no icon + is displayed. + + Events: + 'buttonclick' - fired on button click. + 'linkclick' - fired on link click. + +--> +<polymer-element name="notification-card" + attributes="buttonLabel linkLabel heading type"> + <template> + <link rel="stylesheet" href="notification_card.css"> + + <div id="container" vertical layout center fit> + <div flex vertical layout center center-justified> + <div id="icon-container" vertical layout center hidden?="{{!type}}"> + <template if="{{type == 'fail'}}"> + <core-icon icon="warning"></core-icon> + </template> + <template if="{{type == 'success'}}"> + <core-icon icon="done"></core-icon> + </template> + </div> + <div id="heading" hidden?="{{!heading}}"> + {{heading}} + </div> + <div id="text-container"> + <content></content> + </div> + </div> + <div self-stretch horizontal reverse layout justified center> + <paper-button on-tap="{{buttonClicked}}"> + {{buttonLabel}} + </paper-button> + <a href="#" on-click="{{linkClicked}}" hidden?="{{!linkLabel}}"> + {{linkLabel}} + </a> + </div> + </div> + </template> +</polymer-element>
diff --git a/chrome/browser/resources/chromeos/login/notification_card.js b/chrome/browser/resources/chromeos/login/notification_card.js new file mode 100644 index 0000000..edc91a8 --- /dev/null +++ b/chrome/browser/resources/chromeos/login/notification_card.js
@@ -0,0 +1,16 @@ +// 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. + +Polymer('notification-card', (function() { + return { + buttonClicked: function() { + this.fire('buttonclick'); + }, + + linkClicked: function(e) { + this.fire('linkclick'); + e.preventDefault(); + } + }; +})());
diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.html b/chrome/browser/resources/chromeos/login/screen_gaia_signin.html index 93f80843..218a7d9 100644 --- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.html +++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.html
@@ -31,13 +31,10 @@ <div class="throbber"></div> <throbber-notice i18n-values="text:gaiaLoadingNewGaia"></throbber-notice> </div> - <gaia-whitelist-error - i18n-values="errorMsg:whitelistErrorConsumer; - enterpriseErrorMsg:whitelistErrorEnterprise; - tryAgainBtn:tryAgainButton; - learnMoreBtn:learnMoreButton" - id="gaia-whitelist-error"> - </gaia-whitelist-error> + <notification-card id="gaia-whitelist-error" type="fail" + i18n-values="buttonLabel:tryAgainButton; + linkLabel:learnMoreButton"> + </notification-card> <div id="enterprise-info-container" hidden> <include src="enterprise_info.html"> </div>
diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js index e6ed735..0ae93ea3 100644 --- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js +++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
@@ -16,6 +16,9 @@ /** @const */ var HELP_TOPIC_ENTERPRISE_REPORTING = 2535613; + // The help topic regarding user not being in the whitelist. + /** @const */ var HELP_CANT_ACCESS_ACCOUNT = 188036; + return { EXTERNAL_API: [ 'loadAuthExtension', @@ -151,12 +154,21 @@ $('back-button-item').hidden = true; $('signin-frame').back(); e.preventDefault(); - }.bind(this)); + }); + $('close-button-item').addEventListener('click', function(e) { this.cancel(); e.preventDefault(); }.bind(this)); + $('gaia-whitelist-error').addEventListener('buttonclick', function() { + this.showWhitelistCheckFailedError(false); + }.bind(this)); + + $('gaia-whitelist-error').addEventListener('linkclick', function() { + chrome.send('launchHelpApp', [HELP_CANT_ACCESS_ACCOUNT]); + }); + this.updateLocalizedContent(); }, @@ -793,9 +805,11 @@ * @param {!Object} opt_data Optional additional information. */ showWhitelistCheckFailedError: function(show, opt_data) { - if (opt_data) { - $('gaia-whitelist-error').enterpriseManaged = - opt_data.enterpriseManaged; + if (show) { + var isManaged = opt_data && opt_data.enterpriseManaged; + $('gaia-whitelist-error').textContent = + loadTimeData.getValue(isManaged ? 'whitelistErrorEnterprise' : + 'whitelistErrorConsumer'); } this.classList.toggle('whitelist-error', show);
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/js/constants.js b/chrome/browser/resources/chromeos/wallpaper_manager/js/constants.js index 93de962..8001c16 100644 --- a/chrome/browser/resources/chromeos/wallpaper_manager/js/constants.js +++ b/chrome/browser/resources/chromeos/wallpaper_manager/js/constants.js
@@ -5,14 +5,14 @@ /** @const */ var Constants = { /** - * Key to access wallpaper rss in chrome.local.storage. + * Key to access wallpaper rss in chrome.storage.local. */ - AccessRssKey: 'wallpaper-picker-surprise-rss-key', + AccessLocalRssKey: 'wallpaper-picker-surprise-rss-key', /** * Key to access wallpaper manifest in chrome.storage.local. */ - AccessManifestKey: 'wallpaper-picker-manifest-key', + AccessLocalManifestKey: 'wallpaper-picker-manifest-key', /** * Key to access user wallpaper info in chrome.storage.local. @@ -25,15 +25,22 @@ AccessSyncWallpaperInfoKey: 'wallpaper-sync-info-key', /** - * Key to access last changed date of a surprise wallpaper. + * Key to access last changed date of a surprise wallpaper in + * chrome.storage.local or chrome.storage.sync. */ AccessLastSurpriseWallpaperChangedDate: 'wallpaper-last-changed-date-key', /** * Key to access if surprise me feature is enabled or not in - * chrome.local.storage. + * chrome.storage.local. */ - AccessSurpriseMeEnabledKey: 'surprise-me-enabled-key', + AccessLocalSurpriseMeEnabledKey: 'surprise-me-enabled-key', + + /** + * Key to access if surprise me feature is enabled or not in + * chrome.storage.sync. + */ + AccessSyncSurpriseMeEnabledKey: 'sync-surprise-me-enabled-key', /** * Suffix to append to baseURL if requesting high resoultion wallpaper.
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js b/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js index 738f799..ec17c1fe 100644 --- a/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js +++ b/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js
@@ -40,8 +40,8 @@ // wallpaper picker. If any other error occurs, proceed with local copy of // rss. WallpaperUtil.fetchURL(Constants.WallpaperRssURL, 'document', function(xhr) { - WallpaperUtil.saveToStorage(Constants.AccessRssKey, - new XMLSerializer().serializeToString(xhr.responseXML), false); + WallpaperUtil.saveToLocalStorage(Constants.AccessLocalRssKey, + new XMLSerializer().serializeToString(xhr.responseXML)); self.updateSurpriseWallpaper(xhr.responseXML); }, onFailure); }; @@ -62,8 +62,9 @@ */ SurpriseWallpaper.prototype.fallbackToLocalRss_ = function() { var self = this; - Constants.WallpaperLocalStorage.get(Constants.AccessRssKey, function(items) { - var rssString = items[Constants.AccessRssKey]; + Constants.WallpaperLocalStorage.get(Constants.AccessLocalRssKey, + function(items) { + var rssString = items[Constants.AccessLocalRssKey]; if (rssString) { self.updateSurpriseWallpaper(new DOMParser().parseFromString(rssString, 'text/xml')); @@ -119,13 +120,21 @@ */ SurpriseWallpaper.prototype.updateRandomWallpaper_ = function() { var self = this; - Constants.WallpaperSyncStorage.get( - Constants.AccessLastSurpriseWallpaperChangedDate, function(items) { + var onSuccess = function(items) { var dateString = new Date().toDateString(); // At most one random wallpaper per day. if (items[Constants.AccessLastSurpriseWallpaperChangedDate] != dateString) { self.setRandomWallpaper_(dateString); } + }; + WallpaperUtil.enabledSyncThemesCallback(function(syncEnabled) { + if (syncEnabled) { + Constants.WallpaperSyncStorage.get( + Constants.AccessLastSurpriseWallpaperChangedDate, onSuccess); + } else { + Constants.WallpaperLocalStorage.get( + Constants.AccessLastSurpriseWallpaperChangedDate, onSuccess); + } }); }; @@ -138,9 +147,9 @@ */ SurpriseWallpaper.prototype.setRandomWallpaper_ = function(dateString) { var self = this; - Constants.WallpaperLocalStorage.get(Constants.AccessManifestKey, + Constants.WallpaperLocalStorage.get(Constants.AccessLocalManifestKey, function(items) { - var manifest = items[Constants.AccessManifestKey]; + var manifest = items[Constants.AccessLocalManifestKey]; if (manifest && manifest.wallpaper_list) { var filtered = manifest.wallpaper_list.filter(function(element) { // Older version manifest do not have available_for_surprise_me field. @@ -154,10 +163,13 @@ var onSuccess = function() { WallpaperUtil.saveWallpaperInfo(wallpaperURL, wallpaper.default_layout, Constants.WallpaperSourceEnum.Online); - WallpaperUtil.saveToStorage( + WallpaperUtil.saveToLocalStorage( Constants.AccessLastSurpriseWallpaperChangedDate, - dateString, - true); + dateString, function() { + WallpaperUtil.saveToSyncStorage( + Constants.AccessLastSurpriseWallpaperChangedDate, + dateString); + }); }; WallpaperUtil.setOnlineWallpaper(wallpaperURL, wallpaper.default_layout, onSuccess, self.retryLater_.bind(self)); @@ -188,8 +200,12 @@ WallpaperUtil.saveWallpaperInfo(url, layout, Constants.WallpaperSourceEnum.Online); var dateString = new Date().toDateString(); - WallpaperUtil.saveToStorage( - Constants.AccessLastSurpriseWallpaperChangedDate, dateString, true); + WallpaperUtil.saveToLocalStorage( + Constants.AccessLastSurpriseWallpaperChangedDate, + dateString, function() { + WallpaperUtil.saveToSyncStorage( + Constants.AccessLastSurpriseWallpaperChangedDate, dataString); + }); } else { self.updateRandomWallpaper_(); } @@ -202,8 +218,11 @@ SurpriseWallpaper.prototype.disable = function() { chrome.alarms.clearAll(); // Makes last changed date invalid. - WallpaperUtil.saveToStorage(Constants.AccessLastSurpriseWallpaperChangedDate, - '', true); + WallpaperUtil.saveToLocalStorage( + Constants.AccessLastSurpriseWallpaperChangedDate, '', function() { + WallpaperUtil.saveToSyncStorage( + Constants.AccessLastSurpriseWallpaperChangedDate, ''); + }); }; /** @@ -250,7 +269,9 @@ }); chrome.syncFileSystem.onFileStatusChanged.addListener(function(detail) { - WallpaperUtil.enabledSyncThemesCallback(function() { + WallpaperUtil.enabledSyncThemesCallback(function(syncEnabled) { + if (!syncEnabled) + return; if (detail.status == 'synced' && detail.direction == 'remote_to_local') { if (detail.action == 'added') { @@ -279,69 +300,85 @@ }); chrome.storage.onChanged.addListener(function(changes, namespace) { - WallpaperUtil.enabledSyncThemesCallback(function() { - WallpaperUtil.requestSyncFS(function() {}); - if (changes[Constants.AccessSurpriseMeEnabledKey]) { - if (changes[Constants.AccessSurpriseMeEnabledKey].newValue) { - SurpriseWallpaper.getInstance().next(); - } else { - SurpriseWallpaper.getInstance().disable(); + WallpaperUtil.enabledSyncThemesCallback(function(syncEnabled) { + if (syncEnabled) { + // If sync theme is enabled, use values from chrome.storage.sync to sync + // wallpaper changes. + WallpaperUtil.requestSyncFS(function() {}); + if (changes[Constants.AccessSyncSurpriseMeEnabledKey]) { + if (changes[Constants.AccessSyncSurpriseMeEnabledKey].newValue) { + SurpriseWallpaper.getInstance().next(); + } else { + SurpriseWallpaper.getInstance().disable(); + } } - } - if (changes[Constants.AccessSyncWallpaperInfoKey]) { - var syncInfo = changes[Constants.AccessSyncWallpaperInfoKey].newValue; - - Constants.WallpaperSyncStorage.get(Constants.AccessSurpriseMeEnabledKey, - function(enabledItems) { - var syncSurpriseMeEnabled = - enabledItems[Constants.AccessSurpriseMeEnabledKey]; + if (changes[Constants.AccessSyncWallpaperInfoKey]) { + var syncInfo = changes[Constants.AccessSyncWallpaperInfoKey].newValue; Constants.WallpaperSyncStorage.get( - Constants.AccessLastSurpriseWallpaperChangedDate, function(items) { - var syncLastSurpriseMeChangedDate = - items[Constants.AccessLastSurpriseWallpaperChangedDate]; + Constants.AccessSyncSurpriseMeEnabledKey, function(enabledItems) { + var syncSurpriseMeEnabled = + enabledItems[Constants.AccessSyncSurpriseMeEnabledKey]; - var today = new Date().toDateString(); - // If SurpriseMe is enabled and surprise wallpaper hasn't been changed - // today, we should not sync the change, instead onAlarm() will be - // triggered to update a surprise me wallpaper. - if (!syncSurpriseMeEnabled || - (syncSurpriseMeEnabled && - syncLastSurpriseMeChangedDate == today)) { - Constants.WallpaperLocalStorage.get( - Constants.AccessLocalWallpaperInfoKey, function(infoItems) { - var localInfo = infoItems[Constants.AccessLocalWallpaperInfoKey]; - // Normally, the wallpaper info saved in local storage and sync - // storage are the same. If the synced value changed by sync - // service, they may different. In that case, change wallpaper to - // the one saved in sync storage and update the local value. - if (localInfo == undefined || - localInfo.url != syncInfo.url || - localInfo.layout != syncInfo.layout || - localInfo.source != syncInfo.source) { - if (syncInfo.source == Constants.WallpaperSourceEnum.Online) { - // TODO(bshe): Consider schedule an alarm to set online - // wallpaper later when failed. Note that we need to cancel - // the retry if user set another wallpaper before retry alarm - // invoked. - WallpaperUtil.setOnlineWallpaper(syncInfo.url, - syncInfo.layout, function() {}, function() {}); - } else if (syncInfo.source == - Constants.WallpaperSourceEnum.Custom) { - WallpaperUtil.setCustomWallpaperFromSyncFS(syncInfo.url, - syncInfo.layout); - } else if (syncInfo.source == + Constants.WallpaperSyncStorage.get( + Constants.AccessLastSurpriseWallpaperChangedDate, + function(items) { + var syncLastSurpriseMeChangedDate = + items[Constants.AccessLastSurpriseWallpaperChangedDate]; + + var today = new Date().toDateString(); + // If SurpriseMe is enabled and surprise wallpaper hasn't been + // changed today, we should not sync the change, instead onAlarm() + // will be triggered to update a surprise me wallpaper. + if (!syncSurpriseMeEnabled || + (syncSurpriseMeEnabled && + syncLastSurpriseMeChangedDate == today)) { + Constants.WallpaperLocalStorage.get( + Constants.AccessLocalWallpaperInfoKey, function(infoItems) { + var localInfo = + infoItems[Constants.AccessLocalWallpaperInfoKey]; + // Normally, the wallpaper info saved in local storage and sync + // storage are the same. If the synced value changed by sync + // service, they may different. In that case, change wallpaper + // to the one saved in sync storage and update the local value. + if (localInfo == undefined || + localInfo.url != syncInfo.url || + localInfo.layout != syncInfo.layout || + localInfo.source != syncInfo.source) { + if (syncInfo.source == Constants.WallpaperSourceEnum.Online) { + // TODO(bshe): Consider schedule an alarm to set online + // wallpaper later when failed. Note that we need to cancel + // the retry if user set another wallpaper before retry + // alarm invoked. + WallpaperUtil.setOnlineWallpaper(syncInfo.url, + syncInfo.layout, function() {}, function() {}); + } else if (syncInfo.source == + Constants.WallpaperSourceEnum.Custom) { + WallpaperUtil.setCustomWallpaperFromSyncFS(syncInfo.url, + syncInfo.layout); + } else if (syncInfo.source == Constants.WallpaperSourceEnum.Default) { - chrome.wallpaperPrivate.resetWallpaper(); + chrome.wallpaperPrivate.resetWallpaper(); + } + WallpaperUtil.saveToLocalStorage( + Constants.AccessLocalWallpaperInfoKey, syncInfo); } - WallpaperUtil.saveToStorage( - Constants.AccessLocalWallpaperInfoKey, syncInfo, false); - } - }); - } + }); + } + }); }); - }); + } + } else { + // If sync theme is disabled, use values from chrome.storage.local to + // track wallpaper changes. + if (changes[Constants.AccessLocalSurpriseMeEnabledKey]) { + if (changes[Constants.AccessLocalSurpriseMeEnabledKey].newValue) { + SurpriseWallpaper.getInstance().next(); + } else { + SurpriseWallpaper.getInstance().disable(); + } + } } }); }); @@ -351,7 +388,10 @@ }); chrome.wallpaperPrivate.onWallpaperChangedBy3rdParty.addListener(function() { - WallpaperUtil.saveToStorage(Constants.AccessSurpriseMeEnabledKey, - false, true); + WallpaperUtil.saveToLocalStorage( + Constants.AccessLocalSurpriseMeEnabledKey, false, function() { + WallpaperUtil.saveToSyncStorage(Constants.AccessSyncSurpriseMeEnabledKey, + false); + }); SurpriseWallpaper.getInstance().disable(); });
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/js/util.js b/chrome/browser/resources/chromeos/wallpaper_manager/js/util.js index 3e01d55..de8c5187 100644 --- a/chrome/browser/resources/chromeos/wallpaper_manager/js/util.js +++ b/chrome/browser/resources/chromeos/wallpaper_manager/js/util.js
@@ -89,14 +89,12 @@ }; /** - * Executes callback if sync theme is enabled. - * @param {function} callback The callback will be executed if sync themes is - * enabled. + * Executes callback after requesting the sync settings. + * @param {function} callback The callback will be executed. */ WallpaperUtil.enabledSyncThemesCallback = function(callback) { chrome.wallpaperPrivate.getSyncSetting(function(setting) { - if (setting.syncThemes) - callback(); + callback(setting.syncThemes); }); }; @@ -106,7 +104,9 @@ * handler is available. */ WallpaperUtil.requestSyncFS = function(callback) { - WallpaperUtil.enabledSyncThemesCallback(function() { + WallpaperUtil.enabledSyncThemesCallback(function(syncEnabled) { + if (!syncEnabled) + return; if (WallpaperUtil.syncFs) { callback(WallpaperUtil.syncFs); } else { @@ -264,18 +264,28 @@ * Saves value to local storage that associates with key. * @param {string} key The key that associates with value. * @param {string} value The value to save to local storage. - * @param {boolen} sync True if the value is saved to sync storage. - * @param {function=} opt_callback The callback on success, or on failure. + * @param {function=} opt_callback The callback on success. */ -WallpaperUtil.saveToStorage = function(key, value, sync, opt_callback) { +WallpaperUtil.saveToLocalStorage = function(key, value, opt_callback) { var items = {}; items[key] = value; - if (sync) - WallpaperUtil.enabledSyncThemesCallback(function() { + Constants.WallpaperLocalStorage.set(items, opt_callback); +}; + +/** + * Saves value to sync storage that associates with key if sync theme is + * enabled. + * @param {string} key The key that associates with value. + * @param {string} value The value to save to sync storage. + * @param {function=} opt_callback The callback on success. + */ +WallpaperUtil.saveToSyncStorage = function(key, value, opt_callback) { + var items = {}; + items[key] = value; + WallpaperUtil.enabledSyncThemesCallback(function(syncEnabled) { + if (syncEnabled) Constants.WallpaperSyncStorage.set(items, opt_callback); - }); - else - Constants.WallpaperLocalStorage.set(items, opt_callback); + }); }; /** @@ -292,10 +302,10 @@ layout: layout, source: source }; - WallpaperUtil.saveToStorage(Constants.AccessLocalWallpaperInfoKey, - wallpaperInfo, false, function() { - WallpaperUtil.saveToStorage(Constants.AccessSyncWallpaperInfoKey, - wallpaperInfo, true); + WallpaperUtil.saveToLocalStorage(Constants.AccessLocalWallpaperInfoKey, + wallpaperInfo, function() { + WallpaperUtil.saveToSyncStorage(Constants.AccessSyncWallpaperInfoKey, + wallpaperInfo); }); };
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js b/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js index 1a46792..f490701 100644 --- a/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js +++ b/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js
@@ -171,14 +171,15 @@ */ WallpaperManager.prototype.onLoadManifestSuccess_ = function(manifest) { this.manifest_ = manifest; - WallpaperUtil.saveToStorage(Constants.AccessManifestKey, manifest, false); + WallpaperUtil.saveToLocalStorage(Constants.AccessLocalManifestKey, + manifest); this.postManifestDomInit_(); }; // Sets manifest to previously saved object if any and shows connection error. // Called after manifest failed to load. WallpaperManager.prototype.onLoadManifestFailed_ = function() { - var accessManifestKey = Constants.AccessManifestKey; + var accessManifestKey = Constants.AccessLocalManifestKey; var self = this; Constants.WallpaperLocalStorage.get(accessManifestKey, function(items) { self.manifest_ = items[accessManifestKey] ? @@ -198,29 +199,40 @@ var self = this; var checkbox = $('surprise-me').querySelector('#checkbox'); var shouldEnable = !checkbox.classList.contains('checked'); - WallpaperUtil.saveToStorage(Constants.AccessSurpriseMeEnabledKey, - shouldEnable, true, function() { + var onSuccess = function() { if (chrome.runtime.lastError == null) { - if (shouldEnable) { - checkbox.classList.add('checked'); - // Hides the wallpaper set by message if there is any. - $('wallpaper-set-by-message').textContent = ''; - } else { - // Unchecking the "Surprise me" checkbox falls back to the previous - // wallpaper before "Surprise me" was turned on. - if (self.wallpaperGrid_.activeItem) { - self.setSelectedWallpaper_(self.wallpaperGrid_.activeItem); - self.onWallpaperChanged_(self.wallpaperGrid_.activeItem, - self.currentWallpaper_); - } - checkbox.classList.remove('checked'); - } - $('categories-list').disabled = shouldEnable; - $('wallpaper-grid').disabled = shouldEnable; + if (shouldEnable) { + checkbox.classList.add('checked'); + // Hides the wallpaper set by message if there is any. + $('wallpaper-set-by-message').textContent = ''; } else { - // TODO(bshe): show error message to user. - console.error('Failed to save surprise me option to chrome storage.'); + // Unchecking the "Surprise me" checkbox falls back to the previous + // wallpaper before "Surprise me" was turned on. + if (self.wallpaperGrid_.activeItem) { + self.setSelectedWallpaper_(self.wallpaperGrid_.activeItem); + self.onWallpaperChanged_(self.wallpaperGrid_.activeItem, + self.currentWallpaper_); + } + checkbox.classList.remove('checked'); } + $('categories-list').disabled = shouldEnable; + $('wallpaper-grid').disabled = shouldEnable; + } else { + // TODO(bshe): show error message to user. + console.error('Failed to save surprise me option to chrome storage.'); + } + }; + + // To prevent the onChanged event being fired twice, we only save the value + // to sync storage if the sync theme is enabled, otherwise save it to local + // storage. + WallpaperUtil.enabledSyncThemesCallback(function(syncEnabled) { + if (syncEnabled) + WallpaperUtil.saveToSyncStorage( + Constants.AccessSyncSurpriseMeEnabledKey, shouldEnable, onSuccess); + else + WallpaperUtil.saveToLocalStorage( + Constants.AccessLocalSurpriseMeEnabledKey, shouldEnable, onSuccess); }); }; @@ -272,29 +284,49 @@ $('surprise-me').hidden = false; $('surprise-me').addEventListener('click', this.toggleSurpriseMe_.bind(this)); - Constants.WallpaperSyncStorage.get(Constants.AccessSurpriseMeEnabledKey, - function(items) { + var onSurpriseMeEnabled = function() { + $('surprise-me').querySelector('#checkbox').classList.add('checked'); + $('categories-list').disabled = true; + $('wallpaper-grid').disabled = true; + }; + + WallpaperUtil.enabledSyncThemesCallback(function(syncEnabled) { // Surprise me has been moved from local to sync storage, prefer // values from sync, but if unset check local and update synced pref // if applicable. - if (!items.hasOwnProperty(Constants.AccessSurpriseMeEnabledKey)) { - Constants.WallpaperLocalStorage.get( - Constants.AccessSurpriseMeEnabledKey, function(values) { - if (values.hasOwnProperty(Constants.AccessSurpriseMeEnabledKey)) { - WallpaperUtil.saveToStorage(Constants.AccessSurpriseMeEnabledKey, - values[Constants.AccessSurpriseMeEnabledKey], true); - } - if (values[Constants.AccessSurpriseMeEnabledKey]) { - $('surprise-me').querySelector('#checkbox').classList.add( - 'checked'); - $('categories-list').disabled = true; - $('wallpaper-grid').disabled = true; + if (syncEnabled) { + Constants.WallpaperSyncStorage.get( + Constants.AccessSyncSurpriseMeEnabledKey, function(items) { + if (items.hasOwnProperty( + Constants.AccessSyncSurpriseMeEnabledKey)) { + if (items[Constants.AccessSyncSurpriseMeEnabledKey]) { + onSurpriseMeEnabled(); + } + } else { + Constants.WallpaperLocalStorage.get( + Constants.AccessLocalSurpriseMeEnabledKey, function(items) { + if (items.hasOwnProperty( + Constants.AccessLocalSurpriseMeEnabledKey)) { + WallpaperUtil.saveToSyncStorage( + Constants.AccessSyncSurpriseMeEnabledKey, + items[Constants.AccessLocalSurpriseMeEnabledKey]); + if (items[Constants.AccessLocalSurpriseMeEnabledKey]) { + onSurpriseMeEnabled(); + } + } + }); } }); - } else if (items[Constants.AccessSurpriseMeEnabledKey]) { - $('surprise-me').querySelector('#checkbox').classList.add('checked'); - $('categories-list').disabled = true; - $('wallpaper-grid').disabled = true; + } else { + Constants.WallpaperLocalStorage.get( + Constants.AccessLocalSurpriseMeEnabledKey, function(items) { + if (items.hasOwnProperty( + Constants.AccessLocalSurpriseMeEnabledKey)) { + if (items[Constants.AccessLocalSurpriseMeEnabledKey]) { + onSurpriseMeEnabled(); + } + } + }); } }); @@ -808,8 +840,8 @@ self.wallpaperGrid_.dataModel.splice(0, 0, wallpaperInfo); self.wallpaperGrid_.selectedItem = wallpaperInfo; self.onWallpaperChanged_(wallpaperInfo, fileName); - WallpaperUtil.saveToStorage(self.currentWallpaper_, layout, - false); + WallpaperUtil.saveToLocalStorage(self.currentWallpaper_, + layout); }; fileWriter.onerror = errorHandler; @@ -942,7 +974,7 @@ self.removeCustomWallpaper(fileName); $('set-wallpaper-layout').disabled = true; } else { - WallpaperUtil.saveToStorage(self.currentWallpaper_, layout, false); + WallpaperUtil.saveToLocalStorage(self.currentWallpaper_, layout); self.onWallpaperChanged_(self.wallpaperGrid_.activeItem, self.currentWallpaper_); }
diff --git a/chrome/browser/resources/component_extension_resources.grd b/chrome/browser/resources/component_extension_resources.grd index 2cd8e6e..d5f5374 100644 --- a/chrome/browser/resources/component_extension_resources.grd +++ b/chrome/browser/resources/component_extension_resources.grd
@@ -175,9 +175,6 @@ <include name="IDR_PDF_PDF_SCRIPTING_API_JS" file="pdf/pdf_scripting_api.js" type="BINDATA" /> <include name="IDR_PDF_ZOOM_MANAGER_JS" file="pdf/zoom_manager.js" type="BINDATA" /> <include name="IDR_PDF_CONTENT_SCRIPT_JS" file="pdf/content_script.js" type="BINDATA" /> - <if expr="is_macosx"> - <include name="IDR_PDF_SCROLLBARS_CSS" file="pdf/scrollbars_mac.css" type="BINDATA" /> - </if> <include name="IDR_PDF_VIEWER_BOOKMARK_CSS" file="pdf/elements/viewer-bookmark/viewer-bookmark.css" type="BINDATA" /> <include name="IDR_PDF_VIEWER_BOOKMARK_HTML" file="pdf/elements/viewer-bookmark/viewer-bookmark.html" type="BINDATA" />
diff --git a/chrome/browser/resources/downloads/downloads.css b/chrome/browser/resources/downloads/downloads.css index 2e72404..10c55ff 100644 --- a/chrome/browser/resources/downloads/downloads.css +++ b/chrome/browser/resources/downloads/downloads.css
@@ -107,7 +107,11 @@ } .title-area { - white-space: nowrap; + display: flex; +} + +.title-area > * { + flex-shrink: 0; } .name,
diff --git a/chrome/browser/resources/extensions/extension_error_overlay.js b/chrome/browser/resources/extensions/extension_error_overlay.js index ca9a0fc6..b406b89 100644 --- a/chrome/browser/resources/extensions/extension_error_overlay.js +++ b/chrome/browser/resources/extensions/extension_error_overlay.js
@@ -416,13 +416,15 @@ } if (ExtensionErrorOverlay.canLoadFileSource(error.source, extensionUrl)) { - var relativeUrl = getRelativeUrl(error.source, extensionUrl); + // slice(1) because pathname starts with a /. + var pathname = new URL(error.source).pathname.slice(1); + // Use pathname instead of relativeUrl. var requestFileSourceArgs = {extensionId: error.extensionId, message: error.message, - pathSuffix: relativeUrl}; + pathSuffix: pathname}; - if (relativeUrl.toLowerCase() == + if (pathname.toLowerCase() == ExtensionErrorOverlay.MANIFEST_FILENAME_) { requestFileSourceArgs.manifestKey = error.manifestKey; requestFileSourceArgs.manifestSpecific = error.manifestSpecific;
diff --git a/chrome/browser/resources/pdf/main.js b/chrome/browser/resources/pdf/main.js index 6900c6dc..07fa2e0 100644 --- a/chrome/browser/resources/pdf/main.js +++ b/chrome/browser/resources/pdf/main.js
@@ -42,18 +42,6 @@ function generateStreamDetailsAndInitViewer() { var url = window.location.search.substring(1); - - // Hack to enable custom scrollbars for print preview on non-retina mac - // displays. Remove after crbug.com/466039 is fixed. - if (url.indexOf(IS_MAC_PARAM) === 0) { - url = url.substring(IS_MAC_PARAM.length); - var link = document.createElement('link'); - link.rel = 'stylesheet'; - link.type = 'text/css'; - link.href = 'scrollbars_mac.css'; - document.getElementsByTagName('head')[0].appendChild(link); - } - var streamDetails = { streamUrl: url, originalUrl: url,
diff --git a/chrome/browser/resources/pdf/pdf_scripting_api.js b/chrome/browser/resources/pdf/pdf_scripting_api.js index fa570aee..84b94b12 100644 --- a/chrome/browser/resources/pdf/pdf_scripting_api.js +++ b/chrome/browser/resources/pdf/pdf_scripting_api.js
@@ -250,8 +250,6 @@ }, }; -var IS_MAC_PARAM = 'isMac&'; - /** * Creates a PDF viewer with a scripting interface. This is basically 1) an * iframe which is navigated to the PDF viewer extension and 2) a scripting @@ -262,11 +260,9 @@ */ function PDFCreateOutOfProcessPlugin(src) { var iframe = window.document.createElement('iframe'); - var isMac = cr.isMac ? IS_MAC_PARAM : ''; iframe.setAttribute( 'src', - 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/index.html?' + - isMac + src); + 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/index.html?' + src); // Prevent the frame from being tab-focusable. iframe.setAttribute('tabindex', '-1'); var client = new PDFScriptingAPI(window);
diff --git a/chrome/browser/resources/pdf/scrollbars_mac.css b/chrome/browser/resources/pdf/scrollbars_mac.css deleted file mode 100644 index aaebda0..0000000 --- a/chrome/browser/resources/pdf/scrollbars_mac.css +++ /dev/null
@@ -1,33 +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. */ - -/* - * Imitate mac scrollbars on non-retina displays to workaround crbug.com/466039. - */ -@media -(-webkit-max-device-pixel-ratio: 1) { - -::-webkit-scrollbar { - height: 14px; - width: 14px; -} - -::-webkit-scrollbar-track, -::-webkit-scrollbar-corner { - background-color: rgb(242,242,242); -} - -::-webkit-scrollbar-thumb:vertical, -::-webkit-scrollbar-thumb:horizontal { - -webkit-border-radius: 7px; - background-color: rgb(198,198,198); - border: 3px solid rgb(242,242,242); -} - -::-webkit-scrollbar-thumb:vertical:hover, -::-webkit-scrollbar-thumb:horizontal:hover { - background-color: rgb(126,126,126); -} - -}
diff --git a/chrome/browser/resources/profiler/profiler.js b/chrome/browser/resources/profiler/profiler.js index 9095872..fd7a65bd 100644 --- a/chrome/browser/resources/profiler/profiler.js +++ b/chrome/browser/resources/profiler/profiler.js
@@ -1070,12 +1070,10 @@ var linenumber = m[2]; var link = addNode(td, 'a', filename + ' [' + linenumber + ']'); - // http://chromesrc.appspot.com is a server I wrote specifically for - // this task. It redirects to the appropriate source file; the file - // paths given by the compiler can be pretty crazy and different - // between platforms. - link.href = 'http://chromesrc.appspot.com/?path=' + - encodeURIComponent(filepath) + '&line=' + linenumber; + + link.href = 'https://code.google.com/p/chromium/codesearch#search/&q=' + + encodeURIComponent(filename) + ':' + linenumber + + '&sq=package:chromium&type=cs'; link.target = '_blank'; return; }
diff --git a/chrome/browser/resources/settings/a11y_page/a11y_page.html b/chrome/browser/resources/settings/a11y_page/a11y_page.html index 173dff9..cf7a15a 100644 --- a/chrome/browser/resources/settings/a11y_page/a11y_page.html +++ b/chrome/browser/resources/settings/a11y_page/a11y_page.html
@@ -11,8 +11,6 @@ <link rel="stylesheet" href="chrome://md-settings/settings_page/settings_page.css"> <link rel="stylesheet" href="a11y_page.css"> <paper-shadow layout vertical cross-fade> - <cr-settings-page-header page="{{}}"></cr-settings-page-header> - <div class="more-a11y-link"> <a href="https://chrome.google.com/webstore/category/collection/accessibility" target="_blank" i18n-content="accessibilityMoreFeaturesLink"></a>
diff --git a/chrome/browser/resources/settings/a11y_page/a11y_page.js b/chrome/browser/resources/settings/a11y_page/a11y_page.js index 4181004..272c704 100644 --- a/chrome/browser/resources/settings/a11y_page/a11y_page.js +++ b/chrome/browser/resources/settings/a11y_page/a11y_page.js
@@ -29,6 +29,15 @@ prefs: null, /** + * Whether the page is a subpage. + * + * @attribute subpage + * @type boolean + * @default false + */ + subpage: false, + + /** * ID of the page. * * @attribute PAGE_ID
diff --git a/chrome/browser/resources/settings/date_time_page/date_time_page.html b/chrome/browser/resources/settings/date_time_page/date_time_page.html index 2bc552a..a11f0d42 100644 --- a/chrome/browser/resources/settings/date_time_page/date_time_page.html +++ b/chrome/browser/resources/settings/date_time_page/date_time_page.html
@@ -10,7 +10,6 @@ <link rel="stylesheet" href="chrome://md-settings/settings_page/settings_page.css"> <link rel="stylesheet" href="date_time_page.css"> <paper-shadow layout vertical cross-fade> - <cr-settings-page-header page="{{}}"></cr-settings-page-header> <div horizontal layout center> <core-label horizontal layout center> <span class="time-zone-label">Time zone:</span>
diff --git a/chrome/browser/resources/settings/date_time_page/date_time_page.js b/chrome/browser/resources/settings/date_time_page/date_time_page.js index 210c753b..f91d327 100644 --- a/chrome/browser/resources/settings/date_time_page/date_time_page.js +++ b/chrome/browser/resources/settings/date_time_page/date_time_page.js
@@ -30,6 +30,15 @@ prefs: null, /** + * Whether the page is a subpage. + * + * @attribute subpage + * @type boolean + * @default false + */ + subpage: false, + + /** * ID of the page. * * @attribute PAGE_ID
diff --git a/chrome/browser/resources/settings/downloads_page/downloads_page.html b/chrome/browser/resources/settings/downloads_page/downloads_page.html index 72b707a..b9947e0 100644 --- a/chrome/browser/resources/settings/downloads_page/downloads_page.html +++ b/chrome/browser/resources/settings/downloads_page/downloads_page.html
@@ -11,7 +11,6 @@ <link rel="stylesheet" href="chrome://md-settings/settings_page/settings_page.css"> <link rel="stylesheet" href="downloads_page.css"> <paper-shadow layout vertical cross-fade> - <cr-settings-page-header page="{{}}"></cr-settings-page-header> <div horizontal layout center> <core-label horizontal layout center> <span class="location-label" i18n-content="downloadsLocationLabel"></span>
diff --git a/chrome/browser/resources/settings/downloads_page/downloads_page.js b/chrome/browser/resources/settings/downloads_page/downloads_page.js index 59d1303..f2581919 100644 --- a/chrome/browser/resources/settings/downloads_page/downloads_page.js +++ b/chrome/browser/resources/settings/downloads_page/downloads_page.js
@@ -30,6 +30,15 @@ prefs: null, /** + * Whether the page is a subpage. + * + * @attribute subpage + * @type boolean + * @default false + */ + subpage: false, + + /** * ID of the page. * * @attribute PAGE_ID
diff --git a/chrome/browser/resources/settings/internet_page/internet_page.html b/chrome/browser/resources/settings/internet_page/internet_page.html new file mode 100644 index 0000000..0b1b285 --- /dev/null +++ b/chrome/browser/resources/settings/internet_page/internet_page.html
@@ -0,0 +1,12 @@ +<link rel="import" href="chrome://resources/polymer/polymer/polymer.html"> +<link rel="import" href="network_summary.html"> + +<polymer-element name="cr-settings-internet-page"> + <template> + <link rel="stylesheet" href="chrome://md-settings/settings_page/settings_page.css"> + <paper-shadow layout vertical cross-fade> + <cr-network-summary></cr-network-summary> + </paper-shadow> + </template> + <script src="internet_page.js"></script> +</polymer-element>
diff --git a/chrome/browser/resources/settings/internet_page/internet_page.js b/chrome/browser/resources/settings/internet_page/internet_page.js new file mode 100644 index 0000000..7b16bb39 --- /dev/null +++ b/chrome/browser/resources/settings/internet_page/internet_page.js
@@ -0,0 +1,58 @@ +// 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. + +/** + * @fileoverview + * 'cr-settings-internet-page' is the settings page containing internet + * settings. + * + * Example: + * + * <core-animated-pages> + * <cr-settings-internet-page prefs="{{prefs}}"> + * </cr-settings-internet-page> + * ... other pages ... + * </core-animated-pages> + * + * @group Chrome Settings Elements + * @element cr-settings-internet-page + */ +Polymer('cr-settings-internet-page', { + publish: { + /** + * ID of the page. + * + * @attribute PAGE_ID + * @const string + */ + PAGE_ID: 'internet', + + /** + * Whether the page is a subpage. + * + * @attribute subpage + * @type boolean + * @default false + */ + subpage: false, + + /** + * Title for the page header and navigation menu. + * + * @attribute pageTitle + * @type string + */ + pageTitle: loadTimeData.getString('internetPageTitle'), + + /** + * Name of the 'core-icon' to show. TODO(stevenjb): Update this with the + * icon for the active internet connection. + * + * @attribute icon + * @type string + * @default 'settings-ethernet' + */ + icon: 'settings-ethernet', + }, +});
diff --git a/chrome/browser/resources/settings/internet_page/network_summary.css b/chrome/browser/resources/settings/internet_page/network_summary.css new file mode 100644 index 0000000..b956a77 --- /dev/null +++ b/chrome/browser/resources/settings/internet_page/network_summary.css
@@ -0,0 +1,7 @@ +/* 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. */ + +cr-network-list-item { + margin-bottom: 10px; +}
diff --git a/chrome/browser/resources/settings/internet_page/network_summary.html b/chrome/browser/resources/settings/internet_page/network_summary.html new file mode 100644 index 0000000..f4de128 --- /dev/null +++ b/chrome/browser/resources/settings/internet_page/network_summary.html
@@ -0,0 +1,27 @@ +<link rel="import" href="chrome://resources/polymer/polymer/polymer.html"> +<link rel="import" href="chrome://resources/cr_elements/cr_network_list_item/cr_network_list_item.html"> +<link rel="import" href="chrome://resources/cr_elements/cr_onc/cr_onc_data.html"> + +<polymer-element name="cr-network-summary"> + <template> + <link rel="stylesheet" href="network_summary.css"> + <div id="summary" vertical layout> + <cr-network-list-item networkState="{{networkStates.Ethernet}}" + hidden?="{{!networkStates.Ethernet}}"> + </cr-network-list-item> + <cr-network-list-item networkState="{{networkStates.WiFi}}" + hidden?="{{!networkStates.WiFi}}"> + </cr-network-list-item> + <cr-network-list-item networkState="{{networkStates.Cellular}}" + hidden?="{{!networkStates.Cellular}}"> + </cr-network-list-item> + <cr-network-list-item networkState="{{networkStates.WiMAX}}" + hidden?="{{!networkStates.WiMAX}}"> + </cr-network-list-item> + <cr-network-list-item networkState="{{networkStates.VPN}}" + hidden?="{{!networkStates.VPN}}"> + </cr-network-list-item> + </div> + </template> + <script src="network_summary.js"></script> +</polymer-element>
diff --git a/chrome/browser/resources/settings/internet_page/network_summary.js b/chrome/browser/resources/settings/internet_page/network_summary.js new file mode 100644 index 0000000..34a4b9a --- /dev/null +++ b/chrome/browser/resources/settings/internet_page/network_summary.js
@@ -0,0 +1,161 @@ +// 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. + +/** + * @fileoverview Polymer element for displaying a summary of network states + * by type: Ethernet, WiFi, Cellular, WiMAX, and VPN. + */ +Polymer('cr-network-summary', { + publish: { + /** + * Network state data for each network type. + * + * @attribute networkStates + * @type {{ + * Ethernet: (CrOncDataElement|undefined), + * WiFi: (CrOncDataElement|undefined), + * Cellular: (CrOncDataElement|undefined), + * WiMAX: (CrOncDataElement|undefined), + * VPN: (CrOncDataElement|undefined) + * }} + * @default {} + */ + networkStates: null, + }, + + /** + * Listener function for chrome.networkingPrivate.onNetworkListChanged event. + * @type {function(!Array<string>)} + * @private + */ + listChangedListener_: null, + + /** + * Listener function for chrome.networkingPrivate.onNetworksChanged event. + * @type {function(!Array<string>)} + * @private + */ + networksChangedListener_: null, + + /** + * Dictionary of GUIDs identifying primary (active) networks for each type. + * @type {Object} + * @private + */ + networkIds_: {}, + + /** @override */ + created: function() { + this.networkStates = {}; + }, + + /** @override */ + attached: function() { + this.getNetworks_(); + + this.listChangedListener_ = this.onNetworkListChangedEvent_.bind(this); + chrome.networkingPrivate.onNetworkListChanged.addListener( + this.listChangedListener_); + + this.networksChangedListener_ = this.onNetworksChangedEvent_.bind(this); + chrome.networkingPrivate.onNetworksChanged.addListener( + this.networksChangedListener_); + }, + + /** @override */ + detached: function() { + chrome.networkingPrivate.onNetworkListChanged.removeListener( + this.listChangedListener_); + + chrome.networkingPrivate.onNetworksChanged.removeListener( + this.networksChangedListener_); + }, + + /** + * @private + */ + onNetworkListChangedEvent_: function() { + this.getNetworks_(); + }, + + /** + * @param {!Array<string>} networkIds The list of changed network GUIDs. + * @private + */ + onNetworksChangedEvent_: function(networkIds) { + networkIds.forEach(function(id) { + if (id in this.networkIds_) { + chrome.networkingPrivate.getState(id, + this.getStateCallback_.bind(this)); + } + }, this); + }, + + /** @private */ + getNetworks_: function() { + var filter = { + networkType: 'All', + visible: true, + configured: false + }; + chrome.networkingPrivate.getNetworks(filter, + this.getNetworksCallback_.bind(this)); + }, + + /** + * @param {!Array<!chrome.networkingPrivate.NetworkStateProperties>} states + * The state properties for all networks. + * @private + */ + getNetworksCallback_: function(states) { + // Clear all active networks. + this.networkIds_ = {}; + + // Get the first (active) state for each type. + var foundTypes = {}; + states.forEach(function(state) { + var type = state.Type; + if (!foundTypes[type]) { + foundTypes[type] = true; + this.updateNetworkState_(type, state); + } + }, this); + + // Set any types not found to null. TODO(stevenjb): Support types that are + // disabled but available with no active network. + var types = ['Ethernet', 'WiFi', 'Cellular', 'WiMAX', 'VPN']; + types.forEach(function(type) { + if (!foundTypes[type]) + this.updateNetworkState_(type, null); + }, this); + }, + + /** + * @param {!chrome.networkingPrivate.NetworkStateProperties} state The state + * properties for the network. + * @private + */ + getStateCallback_: function(state) { + var id = state.GUID; + if (!this.networkIds_[id]) + return; + this.updateNetworkState_(state.Type, state); + }, + + /** + * Creates a CrOncDataElement from the network state (if not null) for 'type'. + * Sets 'networkStates[type]' which will update the cr-network-list-item + * associated with 'type'. + * @param {string} type The network type. + * @param {chrome.networkingPrivate.NetworkStateProperties} state The state + * properties for the network to associate with |type|. May be null if + * there are no networks matching |type|. + * @private + */ + updateNetworkState_: function(type, state) { + this.networkStates[type] = state ? CrOncDataElement.create(state) : null; + if (state) + this.networkIds_[state.GUID] = true; + }, +});
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.css b/chrome/browser/resources/settings/settings_main/settings_main.css index 59f7f0b..73a8a32 100644 --- a/chrome/browser/resources/settings/settings_main/settings_main.css +++ b/chrome/browser/resources/settings/settings_main/settings_main.css
@@ -8,12 +8,19 @@ display: block; } -#outer { +#mainContainer { box-sizing: border-box; height: 100%; overflow: auto; } +#mainContainer > paper-shadow { + -webkit-padding-start: 80px; + background-color: white; + padding-bottom: 40px; + padding-top: 40px; +} + #pageContainer { -webkit-margin-end: 20px; -webkit-margin-start: 20px;
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.html b/chrome/browser/resources/settings/settings_main/settings_main.html index cc96389d..a357f1a8 100644 --- a/chrome/browser/resources/settings/settings_main/settings_main.html +++ b/chrome/browser/resources/settings/settings_main/settings_main.html
@@ -5,22 +5,35 @@ <link rel="import" href="chrome://md-settings/a11y_page/a11y_page.html"> <link rel="import" href="chrome://md-settings/date_time_page/date_time_page.html"> <link rel="import" href="chrome://md-settings/downloads_page/downloads_page.html"> +<link rel="import" href="chrome://md-settings/internet_page/internet_page.html"> +<link rel="import" href="chrome://md-settings/routing/more_routing/more_routing.html"> +<!-- Drivers manage how the URL is read, and how to navigate to URLs. "path" + based driver means URLs like /a11y are generated. For more details, see + http://goo.gl/maQU6V --> +<more-routing-config driver="path"></more-routing-config> <polymer-element name="cr-settings-main"> <template> <link rel="stylesheet" href="settings_main.css"> - <div id="outer"> + <div id="mainContainer"> <content select="core-icon-button"></content> - <core-animated-pages id="pageContainer" selected="{{selectedPageId}}" - valueattr="PAGE_ID" transitions="cross-fade"> - <cr-settings-a11y-page prefs="{{prefs}}"></cr-settings-a11y-page> + <more-route-selector> + <core-animated-pages id="pageContainer" selected="{{selectedPageId}}" + valueattr="PAGE_ID" transitions="cross-fade"> <if expr="chromeos"> - <cr-settings-date-time-page prefs="{{prefs}}"> - </cr-settings-date-time-page> + <cr-settings-internet-page route="/internet"> + </cr-settings-internet-page> </if> - <cr-settings-downloads-page prefs="{{prefs}}"> - </cr-settings-downloads-page> - </core-animated-pages> + <cr-settings-a11y-page prefs="{{prefs}}" route="/a11y"> + </cr-settings-a11y-page> +<if expr="chromeos"> + <cr-settings-date-time-page prefs="{{prefs}}" route="/datetime"> + </cr-settings-date-time-page> +</if> + <cr-settings-downloads-page prefs="{{prefs}}" route="/downloads"> + </cr-settings-downloads-page> + </core-animated-pages> + </more-route-selector> </div> </template> <script src="settings_main.js"></script>
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.js b/chrome/browser/resources/settings/settings_main/settings_main.js index 582cfb4..42fc54a7 100644 --- a/chrome/browser/resources/settings/settings_main/settings_main.js +++ b/chrome/browser/resources/settings/settings_main/settings_main.js
@@ -58,8 +58,7 @@ /** @type {MutationObserverInit} */ { childList: true, }); - this.pages = this.$.pageContainer.items; - this.ensureSelection_(); + this.pageContainerUpdated_(); }, /** @@ -81,7 +80,9 @@ * @private */ pageContainerUpdated_: function() { - this.pages = this.$.pageContainer.items; + this.pages = this.$.pageContainer.items.filter(function(item) { + return !item.subpage; + }); this.ensureSelection_(); }, });
diff --git a/chrome/browser/resources/settings/settings_page/settings_page.css b/chrome/browser/resources/settings/settings_page/settings_page.css index 9a0d23b2..c3a0ea0 100644 --- a/chrome/browser/resources/settings/settings_page/settings_page.css +++ b/chrome/browser/resources/settings/settings_page/settings_page.css
@@ -24,4 +24,3 @@ margin-bottom: 10px; margin-top: 10px; } -
diff --git a/chrome/browser/resources/settings/settings_page/settings_page_header.js b/chrome/browser/resources/settings/settings_page/settings_page_header.js index bd485f74..a36911a 100644 --- a/chrome/browser/resources/settings/settings_page/settings_page_header.js +++ b/chrome/browser/resources/settings/settings_page/settings_page_header.js
@@ -24,5 +24,42 @@ * @default null */ page: null, + + /** + * The current stack of pages being viewed. I.e., may contain subpages. + * + * @attribute pageStack + * @type Array + * @default null + */ + pageStack: null, + + /** + * The selector determining which page is currently selected. + * + * @attribute selector + * @type HTMLElement + * @default null + */ + selector: null, }, + + ready: function() { + this.pageStack = []; + }, + + selectorChanged: function() { + this.selector.addEventListener('core-select', function() { + // core-select gets fired once for deselection and once for selection; + // ignore the deselection case. + if (!this.selector.selectedItem) + return; + + if (this.selector.selectedItem.subpage) { + this.pageStack.push(this.selector.selectedItem); + } else { + this.pageStack = [this.selector.selectedItem]; + } + }.bind(this)); + } });
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd index ccee110..c538c67 100644 --- a/chrome/browser/resources/settings/settings_resources.grd +++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -85,27 +85,27 @@ <structure name="IDR_SETTINGS_DATE_TIME_PAGE_CSS" file="date_time_page/date_time_page.css" type="chrome_html" /> - <structure name="IDR_SETTINGS_DATE_TIME_PAGE_JS" - file="date_time_page/date_time_page.js" - type="chrome_html" /> <structure name="IDR_SETTINGS_DATE_TIME_PAGE_HTML" file="date_time_page/date_time_page.html" type="chrome_html" /> + <structure name="IDR_SETTINGS_DATE_TIME_PAGE_JS" + file="date_time_page/date_time_page.js" + type="chrome_html" /> <structure name="IDR_SETTINGS_DOWNLOADS_PAGE_CSS" file="downloads_page/downloads_page.css" type="chrome_html" /> - <structure name="IDR_SETTINGS_DOWNLOADS_PAGE_JS" - file="downloads_page/downloads_page.js" - type="chrome_html" /> <structure name="IDR_SETTINGS_DOWNLOADS_PAGE_HTML" file="downloads_page/downloads_page.html" type="chrome_html" /> - <structure name="IDR_SETTINGS_PREFS_JS" - file="prefs/prefs.js" + <structure name="IDR_SETTINGS_DOWNLOADS_PAGE_JS" + file="downloads_page/downloads_page.js" type="chrome_html" /> <structure name="IDR_SETTINGS_PREFS_HTML" file="prefs/prefs.html" type="chrome_html" /> + <structure name="IDR_SETTINGS_PREFS_JS" + file="prefs/prefs.js" + type="chrome_html" /> <structure name="IDR_SETTINGS_PREFS_TYPES_JS" file="prefs/prefs_types.js" type="chrome_html" /> @@ -208,6 +208,23 @@ <structure name="IDR_SETTINGS_SETTINGS_JS" file="settings.js" type="chrome_html" /> + <if expr="chromeos"> + <structure name="IDR_SETTINGS_INTERNET_PAGE_HTML" + file="internet_page/internet_page.html" + type="chrome_html" /> + <structure name="IDR_SETTINGS_INTERNET_PAGE_JS" + file="internet_page/internet_page.js" + type="chrome_html" /> + <structure name="IDR_SETTINGS_NETWORK_SUMMARY_CSS" + file="internet_page/network_summary.css" + type="chrome_html" /> + <structure name="IDR_SETTINGS_NETWORK_SUMMARY_HTML" + file="internet_page/network_summary.html" + type="chrome_html" /> + <structure name="IDR_SETTINGS_NETWORK_SUMMARY_JS" + file="internet_page/network_summary.js" + type="chrome_html" /> + </if> </structures> </release> </grit>
diff --git a/chrome/browser/safe_browsing/database_manager.cc b/chrome/browser/safe_browsing/database_manager.cc index 0327d9f..afcd0f69 100644 --- a/chrome/browser/safe_browsing/database_manager.cc +++ b/chrome/browser/safe_browsing/database_manager.cc
@@ -12,7 +12,6 @@ #include "base/command_line.h" #include "base/debug/leak_tracker.h" #include "base/metrics/histogram_macros.h" -#include "base/profiler/scoped_tracker.h" #include "base/stl_util.h" #include "base/strings/string_util.h" #include "chrome/browser/browser_process.h" @@ -652,9 +651,6 @@ } void SafeBrowsingDatabaseManager::StartOnIOThread() { - // TODO(pkasting): Remove ScopedTracker below once crbug.com/455469 is fixed. - tracked_objects::ScopedTracker tracking_profile1( - FROM_HERE_WITH_EXPLICIT_FUNCTION("455469 StartOnIOThread")); DCHECK_CURRENTLY_ON(BrowserThread::IO); if (enabled_) return;
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc index 53e26ba..d657e661 100644 --- a/chrome/browser/safe_browsing/safe_browsing_service.cc +++ b/chrome/browser/safe_browsing/safe_browsing_service.cc
@@ -393,6 +393,10 @@ void SafeBrowsingService::InitURLRequestContextOnIOThread( net::URLRequestContextGetter* system_url_request_context_getter) { + // TODO(pkasting): Remove ScopedTracker below once crbug.com/455469 is fixed. + tracked_objects::ScopedTracker tracking_profile1( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "455469 SafeBrowsingService::InitURLRequestContextOnIOThread 1")); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DCHECK(!url_request_context_.get()); @@ -404,6 +408,10 @@ NULL, NULL))); + // TODO(pkasting): Remove ScopedTracker below once crbug.com/455469 is fixed. + tracked_objects::ScopedTracker tracking_profile2( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "455469 SafeBrowsingService::InitURLRequestContextOnIOThread 2")); url_request_context_.reset(new net::URLRequestContext); // |system_url_request_context_getter| may be NULL during tests. if (system_url_request_context_getter) { @@ -464,6 +472,10 @@ void SafeBrowsingService::StartOnIOThread( net::URLRequestContextGetter* url_request_context_getter) { + // TODO(pkasting): Remove ScopedTracker below once crbug.com/455469 is fixed. + tracked_objects::ScopedTracker tracking_profile1( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "455469 SafeBrowsingService::StartOnIOThread 1")); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); if (enabled_) return; @@ -472,15 +484,27 @@ SafeBrowsingProtocolConfig config = GetProtocolConfig(); #if defined(FULL_SAFE_BROWSING) + // TODO(pkasting): Remove ScopedTracker below once crbug.com/455469 is fixed. + tracked_objects::ScopedTracker tracking_profile2( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "455469 SafeBrowsingService::StartOnIOThread 2")); DCHECK(database_manager_.get()); database_manager_->StartOnIOThread(); + // TODO(pkasting): Remove ScopedTracker below once crbug.com/455469 is fixed. + tracked_objects::ScopedTracker tracking_profile3( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "455469 SafeBrowsingService::StartOnIOThread 3")); DCHECK(!protocol_manager_); protocol_manager_ = SafeBrowsingProtocolManager::Create( database_manager_.get(), url_request_context_getter, config); protocol_manager_->Initialize(); #endif + // TODO(pkasting): Remove ScopedTracker below once crbug.com/455469 is fixed. + tracked_objects::ScopedTracker tracking_profile4( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "455469 SafeBrowsingService::StartOnIOThread 4")); DCHECK(!ping_manager_); ping_manager_ = SafeBrowsingPingManager::Create( url_request_context_getter, config);
diff --git a/chrome/browser/sessions/session_restore_delegate.cc b/chrome/browser/sessions/session_restore_delegate.cc index 9a40060..d409d38 100644 --- a/chrome/browser/sessions/session_restore_delegate.cc +++ b/chrome/browser/sessions/session_restore_delegate.cc
@@ -7,6 +7,7 @@ #include "base/metrics/field_trial.h" #include "chrome/browser/sessions/session_restore_stats_collector.h" #include "chrome/browser/sessions/tab_loader.h" +#include "components/favicon/content/content_favicon_driver.h" // static void SessionRestoreDelegate::RestoreTabs( @@ -20,6 +21,16 @@ if (!trial || trial->group_name() == "Restore") { TabLoader::RestoreTabs(tabs, restore_started); active_only = false; + } else { + // If we are not loading inactive tabs, restore their favicons (title has + // already been set by now). + for (auto& tab : tabs) { + if (!tab.is_active) { + favicon::ContentFaviconDriver* favicon_driver = + favicon::ContentFaviconDriver::FromWebContents(tab.contents); + favicon_driver->FetchFavicon(favicon_driver->GetActiveURL()); + } + } } SessionRestoreStatsCollector::TrackTabs(tabs, restore_started, active_only); }
diff --git a/chrome/browser/signin/chrome_signin_client.cc b/chrome/browser/signin/chrome_signin_client.cc index 680c9e9..debf8eca4 100644 --- a/chrome/browser/signin/chrome_signin_client.cc +++ b/chrome/browser/signin/chrome_signin_client.cc
@@ -23,6 +23,7 @@ #include "components/signin/core/common/profile_management_switches.h" #include "components/signin/core/common/signin_pref_names.h" #include "components/signin/core/common/signin_switches.h" +#include "google_apis/gaia/gaia_urls.h" #include "net/url_request/url_request_context_getter.h" #include "url/gurl.h" @@ -38,12 +39,6 @@ #include "chrome/browser/first_run/first_run.h" #endif -namespace { - -const char kGoogleAccountsUrl[] = "https://accounts.google.com"; - -} // namespace - ChromeSigninClient::ChromeSigninClient( Profile* profile, SigninErrorController* signin_error_controller) : profile_(profile), @@ -65,9 +60,9 @@ // static bool ChromeSigninClient::SettingsAllowSigninCookies( CookieSettings* cookie_settings) { + GURL gaia_url = GaiaUrls::GetInstance()->gaia_url(); return cookie_settings && - cookie_settings->IsSettingCookieAllowed(GURL(kGoogleAccountsUrl), - GURL(kGoogleAccountsUrl)); + cookie_settings->IsSettingCookieAllowed(gaia_url, gaia_url); } PrefService* ChromeSigninClient::GetPrefs() { return profile_->GetPrefs(); }
diff --git a/chrome/browser/sync/glue/password_data_type_controller.cc b/chrome/browser/sync/glue/password_data_type_controller.cc index 354d8f9..71b589a 100644 --- a/chrome/browser/sync/glue/password_data_type_controller.cc +++ b/chrome/browser/sync/glue/password_data_type_controller.cc
@@ -10,6 +10,8 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sync/glue/chrome_report_unrecoverable_error.h" #include "chrome/browser/sync/profile_sync_components_factory.h" +#include "chrome/browser/sync/profile_sync_service.h" +#include "chrome/browser/sync/profile_sync_service_factory.h" #include "components/password_manager/core/browser/password_store.h" #include "content/public/browser/browser_thread.h" @@ -50,9 +52,29 @@ bool PasswordDataTypeController::StartModels() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK_EQ(MODEL_STARTING, state()); + + ProfileSyncService* profile_sync_service = + ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile_); + DCHECK(profile_sync_service); + profile_sync_service->AddObserver(this); + + OnStateChanged(); + password_store_ = PasswordStoreFactory::GetForProfile( profile_, ServiceAccessType::EXPLICIT_ACCESS); return !!password_store_.get(); } +void PasswordDataTypeController::StopModels() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + ProfileSyncService* profile_sync_service = + ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile_); + DCHECK(profile_sync_service); + profile_sync_service->RemoveObserver(this); +} + +void PasswordDataTypeController::OnStateChanged() { + PasswordStoreFactory::OnPasswordsSyncedStatePotentiallyChanged(profile_); +} + } // namespace browser_sync
diff --git a/chrome/browser/sync/glue/password_data_type_controller.h b/chrome/browser/sync/glue/password_data_type_controller.h index ae59542..a2bceb4b 100644 --- a/chrome/browser/sync/glue/password_data_type_controller.h +++ b/chrome/browser/sync/glue/password_data_type_controller.h
@@ -9,6 +9,7 @@ #include "base/memory/ref_counted.h" #include "components/sync_driver/non_ui_data_type_controller.h" +#include "components/sync_driver/sync_service_observer.h" class Profile; class ProfileSyncComponentsFactory; @@ -20,7 +21,8 @@ namespace browser_sync { // A class that manages the startup and shutdown of password sync. -class PasswordDataTypeController : public sync_driver::NonUIDataTypeController { +class PasswordDataTypeController : public sync_driver::NonUIDataTypeController, + public sync_driver::SyncServiceObserver { public: PasswordDataTypeController( ProfileSyncComponentsFactory* profile_sync_factory, @@ -37,6 +39,10 @@ bool PostTaskOnBackendThread(const tracked_objects::Location& from_here, const base::Closure& task) override; bool StartModels() override; + void StopModels() override; + + // sync_driver::SyncServiceObserver: + void OnStateChanged() override; private: Profile* const profile_;
diff --git a/chrome/browser/sync/glue/typed_url_model_associator.cc b/chrome/browser/sync/glue/typed_url_model_associator.cc index 373fc7c..e758b385 100644 --- a/chrome/browser/sync/glue/typed_url_model_associator.cc +++ b/chrome/browser/sync/glue/typed_url_model_associator.cc
@@ -162,7 +162,8 @@ syncer::SyncMergeResult* local_merge_result, syncer::SyncMergeResult* syncer_merge_result) { ClearErrorStats(); - syncer::SyncError error = DoAssociateModels(); + syncer::SyncError error = + DoAssociateModels(local_merge_result, syncer_merge_result); UMA_HISTOGRAM_PERCENTAGE("Sync.TypedUrlModelAssociationErrors", GetErrorPercentage()); ClearErrorStats(); @@ -178,7 +179,9 @@ return num_db_accesses_ ? (100 * num_db_errors_ / num_db_accesses_) : 0; } -syncer::SyncError TypedUrlModelAssociator::DoAssociateModels() { +syncer::SyncError TypedUrlModelAssociator::DoAssociateModels( + syncer::SyncMergeResult* local_merge_result, + syncer::SyncMergeResult* syncer_merge_result) { DVLOG(1) << "Associating TypedUrl Models"; DCHECK(expected_loop_ == base::MessageLoop::current()); @@ -207,6 +210,7 @@ "Could not get the typed_url entries.", model_type()); } + local_merge_result->set_num_items_before_association(typed_urls.size()); // Get all the visits. std::map<history::URLID, history::VisitVector> visit_vectors; @@ -234,6 +238,8 @@ "might be running against an out-of-date server.", model_type()); } + syncer_merge_result->set_num_items_before_association( + typed_url_root.GetTotalNodeCount()); std::set<std::string> current_urls; for (history::URLRows::iterator ix = typed_urls.begin(); @@ -288,6 +294,8 @@ DCHECK_EQ(new_url.last_visit().ToInternalValue(), visits.back().visit_time.ToInternalValue()); WriteToSyncNode(new_url, visits, &write_node); + syncer_merge_result->set_num_items_modified( + syncer_merge_result->num_items_modified() + 1); } if (difference & DIFF_LOCAL_ROW_CHANGED) { DCHECK_EQ(ix->id(), new_url.id()); @@ -313,6 +321,8 @@ node.SetTitle(tag); WriteToSyncNode(*ix, visits, &node); + syncer_merge_result->set_num_items_added( + syncer_merge_result->num_items_added() + 1); } current_urls.insert(tag); @@ -373,6 +383,8 @@ NULL, &updated_urls, &new_urls); + local_merge_result->set_num_items_added( + local_merge_result->num_items_added() + 1); } } @@ -392,6 +404,8 @@ sync_node.Tombstone(); } } + syncer_merge_result->set_num_items_after_association( + typed_url_root.GetTotalNodeCount()); } // Since we're on the history thread, we don't have to worry about updating @@ -400,6 +414,10 @@ // to worry about the sync model getting out of sync, because changes are // propagated to the ChangeProcessor on this thread. WriteToHistoryBackend(&new_urls, &updated_urls, &new_visits, NULL); + local_merge_result->set_num_items_modified(updated_urls.size()); + local_merge_result->set_num_items_after_association( + local_merge_result->num_items_before_association() + + local_merge_result->num_items_added()); return syncer::SyncError(); }
diff --git a/chrome/browser/sync/glue/typed_url_model_associator.h b/chrome/browser/sync/glue/typed_url_model_associator.h index 44e9ea7b..8ae5319 100644 --- a/chrome/browser/sync/glue/typed_url_model_associator.h +++ b/chrome/browser/sync/glue/typed_url_model_associator.h
@@ -174,7 +174,9 @@ private: // Helper routine that actually does the work of associating models. - syncer::SyncError DoAssociateModels(); + syncer::SyncError DoAssociateModels( + syncer::SyncMergeResult* local_merge_result, + syncer::SyncMergeResult* syncer_merge_result); // Helper function that determines if we should ignore a URL for the purposes // of sync, based on the visits the URL had.
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc index cff2ac5..2ee3dc2 100644 --- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc +++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
@@ -2448,10 +2448,11 @@ HidePopup(); } -void AutofillDialogControllerImpl::RemoveSuggestion( +bool AutofillDialogControllerImpl::RemoveSuggestion( const base::string16& value, int identifier) { // TODO(estade): implement. + return false; } void AutofillDialogControllerImpl::ClearPreviewedForm() {
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h index 80e5a5fd..27db8f7 100644 --- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h +++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
@@ -169,7 +169,7 @@ int identifier) override; void DidAcceptSuggestion(const base::string16& value, int identifier) override; - void RemoveSuggestion(const base::string16& value, int identifier) override; + bool RemoveSuggestion(const base::string16& value, int identifier) override; void ClearPreviewedForm() override; // content::NotificationObserver implementation.
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller.h b/chrome/browser/ui/autofill/autofill_popup_controller.h index a5a723ca..c1631a0 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller.h +++ b/chrome/browser/ui/autofill/autofill_popup_controller.h
@@ -34,9 +34,6 @@ // resource isn't recognized. virtual int GetIconResourceID(const base::string16& resource_name) const = 0; - // Returns true if the given index refers to an element that can be deleted. - virtual bool CanDelete(size_t index) const = 0; - // Returns true if the given index refers to an element that is a warning // rather than an Autofill suggestion. virtual bool IsWarning(size_t index) const = 0;
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc index 2a659829..5a80f67 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
@@ -356,14 +356,6 @@ return -1; } -bool AutofillPopupControllerImpl::CanDelete(size_t index) const { - // TODO(isherman): Native AddressBook suggestions on Mac and Android should - // not be considered to be deleteable. - int id = suggestions_[index].frontend_id; - return id > 0 || id == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY || - id == POPUP_ITEM_ID_PASSWORD_ENTRY; -} - bool AutofillPopupControllerImpl::IsWarning(size_t index) const { return suggestions_[index].frontend_id == POPUP_ITEM_ID_WARNING_MESSAGE; } @@ -508,11 +500,10 @@ DCHECK_GE(selected_line_, 0); DCHECK_LT(selected_line_, static_cast<int>(GetLineCount())); - if (!CanDelete(selected_line_)) + if (!delegate_->RemoveSuggestion(suggestions_[selected_line_].value, + suggestions_[selected_line_].frontend_id)) { return false; - - delegate_->RemoveSuggestion(suggestions_[selected_line_].value, - suggestions_[selected_line_].frontend_id); + } // Remove the deleted element. suggestions_.erase(suggestions_.begin() + selected_line_);
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.h b/chrome/browser/ui/autofill/autofill_popup_controller_impl.h index 8e84b6cd..1f26da9 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.h +++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.h
@@ -76,7 +76,6 @@ void SelectionCleared() override; void AcceptSuggestion(size_t index) override; int GetIconResourceID(const base::string16& resource_name) const override; - bool CanDelete(size_t index) const override; bool IsWarning(size_t index) const override; gfx::Rect GetRowBounds(size_t index) override; void SetPopupBounds(const gfx::Rect& bounds) override;
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc index 71e262aa..122bcd90 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
@@ -47,7 +47,9 @@ void DidSelectSuggestion(const base::string16& value, int identifier) override {} - void RemoveSuggestion(const base::string16& value, int identifier) override {} + bool RemoveSuggestion(const base::string16& value, int identifier) override { + return true; + } void ClearPreviewedForm() override {} base::WeakPtr<AutofillExternalDelegate> GetWeakPtr() { return AutofillExternalDelegate::GetWeakPtr(); @@ -248,12 +250,6 @@ // No line is selected so the removal should fail. EXPECT_FALSE(autofill_popup_controller_->RemoveSelectedLine()); - // Try to remove the last entry and ensure it fails (it is an option). - autofill_popup_controller_->SetSelectedLine( - autofill_popup_controller_->GetLineCount() - 1); - EXPECT_FALSE(autofill_popup_controller_->RemoveSelectedLine()); - EXPECT_LE(0, autofill_popup_controller_->selected_line()); - // Remove the first entry. The popup should be redrawn since its size has // changed. EXPECT_CALL(*autofill_popup_controller_, UpdateBoundsAndRedrawPopup());
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm index 19f9ac8a..dc640a1 100644 --- a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm +++ b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
@@ -171,9 +171,6 @@ bool IsPopupRunning() const override; void OnOverflowedActionWantsToRunChanged(bool overflowed_action_wants_to_run) override; - void ShowExtensionMessageBubble( - scoped_ptr<extensions::ExtensionMessageBubbleController> controller) - override; // The owning BrowserActionsController; weak. BrowserActionsController* controller_; @@ -251,11 +248,6 @@ setOverflowedToolbarActionWantsToRun:overflowed_action_wants_to_run]; } -void ToolbarActionsBarBridge::ShowExtensionMessageBubble( - scoped_ptr<extensions::ExtensionMessageBubbleController> controller) { - NOTREACHED(); // Not yet implemented on Mac. -} - } // namespace @implementation BrowserActionsController
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm index 617cc56..df7b00d3 100644 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm +++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
@@ -17,6 +17,7 @@ #include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h" #include "chrome/browser/ui/omnibox/omnibox_popup_model.h" #include "chrome/grit/generated_resources.h" +#include "components/omnibox/suggestion_answer.h" #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/font.h" @@ -180,7 +181,23 @@ match_.contents, ContentTextColor(), match_.contents_class); [self setAttributedTitle:contents]; - if (match_.description.empty()) { + if (match_.answer) { + base::string16 answerString; + DCHECK(!match_.answer->second_line().text_fields().empty()); + for (const SuggestionAnswer::TextField& textField : + match_.answer->second_line().text_fields()) + answerString += textField.text(); + const base::char16 space(' '); + const SuggestionAnswer::TextField* textField = + match_.answer->second_line().additional_text(); + if (textField) + answerString += space + textField->text(); + textField = match_.answer->second_line().status_text(); + if (textField) + answerString += space + textField->text(); + description_.reset([CreateClassifiedAttributedString( + answerString, DimTextColor(), match_.description_class) retain]); + } else if (match_.description.empty()) { description_.reset(); } else { description_.reset([CreateClassifiedAttributedString(
diff --git a/chrome/browser/ui/extensions/OWNERS b/chrome/browser/ui/extensions/OWNERS index e7cdf1a..98867c4 100644 --- a/chrome/browser/ui/extensions/OWNERS +++ b/chrome/browser/ui/extensions/OWNERS
@@ -1,9 +1,6 @@ benwells@chromium.org miket@chromium.org +# Extension/Toolbar Actions Files per-file extension_action*=finnur@chromium.org per-file extension_action*=rdevlin.cronin@chromium.org -per-file extension_installed_bubble*=finnur@chromium.org -per-file extension_installed_bubble*=rdevlin.cronin@chromium.org -per-file extension_message_bubble*=finnur@chromium.org -per-file extension_message_bubble*=rdevlin.cronin@chromium.org
diff --git a/chrome/browser/ui/extensions/extension_message_bubble_factory.cc b/chrome/browser/ui/extensions/extension_message_bubble_factory.cc deleted file mode 100644 index 8737602..0000000 --- a/chrome/browser/ui/extensions/extension_message_bubble_factory.cc +++ /dev/null
@@ -1,92 +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/ui/extensions/extension_message_bubble_factory.h" - -#include "base/lazy_instance.h" -#include "chrome/browser/extensions/dev_mode_bubble_controller.h" -#include "chrome/browser/extensions/extension_message_bubble_controller.h" -#include "chrome/browser/extensions/proxy_overridden_bubble_controller.h" -#include "chrome/browser/extensions/settings_api_bubble_controller.h" -#include "chrome/browser/extensions/settings_api_helpers.h" -#include "chrome/browser/extensions/suspicious_extension_bubble_controller.h" -#include "chrome/browser/profiles/profile.h" - -namespace { - -// A map of all profiles evaluated, so we can tell if it's the initial check. -// TODO(devlin): It would be nice to coalesce all the "profiles evaluated" maps -// that are in the different bubble controllers. -base::LazyInstance<std::set<Profile*> > g_profiles_evaluated = - LAZY_INSTANCE_INITIALIZER; - -} - -ExtensionMessageBubbleFactory::ExtensionMessageBubbleFactory(Profile* profile) - : profile_(profile) { -} - -ExtensionMessageBubbleFactory::~ExtensionMessageBubbleFactory() { -} - -scoped_ptr<extensions::ExtensionMessageBubbleController> -ExtensionMessageBubbleFactory::GetController() { -// Currently only on windows. -#if !defined(OS_WIN) - return scoped_ptr<extensions::ExtensionMessageBubbleController>(); -#endif - - Profile* original_profile = profile_->GetOriginalProfile(); - std::set<Profile*>& profiles_evaluated = g_profiles_evaluated.Get(); - bool is_initial_check = profiles_evaluated.count(original_profile) == 0; - profiles_evaluated.insert(original_profile); - - // The list of suspicious extensions takes priority over the dev mode bubble - // and the settings API bubble, since that needs to be shown as soon as we - // disable something. The settings API bubble is shown on first startup after - // an extension has changed the startup pages and it is acceptable if that - // waits until the next startup because of the suspicious extension bubble. - // The dev mode bubble is not time sensitive like the other two so we'll catch - // the dev mode extensions on the next startup/next window that opens. That - // way, we're not too spammy with the bubbles. - { - scoped_ptr<extensions::SuspiciousExtensionBubbleController> controller( - new extensions::SuspiciousExtensionBubbleController(profile_)); - if (controller->ShouldShow()) - return controller.Pass(); - } - - { - // No use showing this if it's not the startup of the profile. - if (is_initial_check) { - scoped_ptr<extensions::SettingsApiBubbleController> controller( - new extensions::SettingsApiBubbleController( - profile_, extensions::BUBBLE_TYPE_STARTUP_PAGES)); - if (controller->ShouldShow()) - return controller.Pass(); - } - } - - { - // TODO(devlin): Move the "GetExtensionOverridingProxy" part into the - // proxy bubble controller. - const extensions::Extension* extension = - extensions::GetExtensionOverridingProxy(profile_); - if (extension) { - scoped_ptr<extensions::ProxyOverriddenBubbleController> controller( - new extensions::ProxyOverriddenBubbleController(profile_)); - if (controller->ShouldShow(extension->id())) - return controller.Pass(); - } - } - - { - scoped_ptr<extensions::DevModeBubbleController> controller( - new extensions::DevModeBubbleController(profile_)); - if (controller->ShouldShow()) - return controller.Pass(); - } - - return scoped_ptr<extensions::ExtensionMessageBubbleController>(); -}
diff --git a/chrome/browser/ui/extensions/extension_message_bubble_factory.h b/chrome/browser/ui/extensions/extension_message_bubble_factory.h deleted file mode 100644 index 703cd30..0000000 --- a/chrome/browser/ui/extensions/extension_message_bubble_factory.h +++ /dev/null
@@ -1,34 +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_UI_EXTENSIONS_EXTENSION_MESSAGE_BUBBLE_FACTORY_H_ -#define CHROME_BROWSER_UI_EXTENSIONS_EXTENSION_MESSAGE_BUBBLE_FACTORY_H_ - -#include "base/macros.h" -#include "base/memory/scoped_ptr.h" - -class Profile; - -namespace extensions { -class ExtensionMessageBubbleController; -} // namespace extensions - -// Create and show ExtensionMessageBubbles for either extensions that look -// suspicious and have therefore been disabled, or for extensions that are -// running in developer mode that we want to warn the user about. -class ExtensionMessageBubbleFactory { - public: - explicit ExtensionMessageBubbleFactory(Profile* profile); - ~ExtensionMessageBubbleFactory(); - - // Returns the controller for the bubble that should be shown, if any. - scoped_ptr<extensions::ExtensionMessageBubbleController> GetController(); - - private: - Profile* profile_; - - DISALLOW_COPY_AND_ASSIGN(ExtensionMessageBubbleFactory); -}; - -#endif // CHROME_BROWSER_UI_EXTENSIONS_EXTENSION_MESSAGE_BUBBLE_FACTORY_H_
diff --git a/chrome/browser/ui/libgtk2ui/gtk2_ui.cc b/chrome/browser/ui/libgtk2ui/gtk2_ui.cc index 2f7f2cd9..a57b59f 100644 --- a/chrome/browser/ui/libgtk2ui/gtk2_ui.cc +++ b/chrome/browser/ui/libgtk2ui/gtk2_ui.cc
@@ -380,16 +380,20 @@ return params; } -// Queries GTK for its font DPI setting and returns the number of pixels in a -// point. -double GetPixelsInPoint(float device_scale_factor) { +double GetDPI() { 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. - double dpi = (gtk_dpi > 0) ? gtk_dpi / 1024.0 : 96.0; + return (gtk_dpi > 0) ? gtk_dpi / 1024.0 : 96.0; +} + +// 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(); // Take device_scale_factor into account — if Chrome already scales the // entire UI up by 2x, we should not also scale up. @@ -1420,6 +1424,12 @@ UpdateDefaultFont(label_style->font_desc); } +float Gtk2UI::GetDeviceScaleFactor() const { + const int kCSSDefaultDPI = 96; + const float scale = GetDPI() / kCSSDefaultDPI; + return ui::GetScaleForScaleFactor(ui::GetSupportedScaleFactor(scale)); +} + } // namespace libgtk2ui views::LinuxUI* BuildGtk2UI() {
diff --git a/chrome/browser/ui/libgtk2ui/gtk2_ui.h b/chrome/browser/ui/libgtk2ui/gtk2_ui.h index 209390d9..cd0918a7 100644 --- a/chrome/browser/ui/libgtk2ui/gtk2_ui.h +++ b/chrome/browser/ui/libgtk2ui/gtk2_ui.h
@@ -121,6 +121,7 @@ // ui::Views::LinuxUI: void UpdateDeviceScaleFactor(float device_scale_factor) override; + float GetDeviceScaleFactor() const override; private: typedef std::map<int, SkColor> ColorMap;
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar.cc b/chrome/browser/ui/toolbar/toolbar_actions_bar.cc index a3323ed..be3687c 100644 --- a/chrome/browser/ui/toolbar/toolbar_actions_bar.cc +++ b/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
@@ -7,14 +7,12 @@ #include "base/auto_reset.h" #include "base/profiler/scoped_tracker.h" #include "chrome/browser/extensions/extension_action_manager.h" -#include "chrome/browser/extensions/extension_message_bubble_controller.h" #include "chrome/browser/extensions/extension_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sessions/session_tab_helper.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/extensions/extension_action_view_controller.h" -#include "chrome/browser/ui/extensions/extension_message_bubble_factory.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" #include "chrome/browser/ui/toolbar/component_toolbar_actions_factory.h" @@ -420,8 +418,7 @@ model_observer_(this), suppress_layout_(false), suppress_animation_(true), - overflowed_action_wants_to_run_(false), - checked_extension_bubble_(false) { + overflowed_action_wants_to_run_(false) { if (model_) // |model_| can be null in unittests. model_observer_.Add(model_); @@ -634,11 +631,6 @@ // Once the actions are created, we should animate the changes. suppress_animation_ = false; - - // CreateActions() can be called multiple times, so we need to make sure we - // haven't already shown the bubble. - if (!checked_extension_bubble_) - MaybeShowExtensionBubble(); } void ToolbarActionsBar::DeleteActions() { @@ -737,16 +729,6 @@ return true; } -void ToolbarActionsBar::MaybeShowExtensionBubble() { - checked_extension_bubble_ = true; - scoped_ptr<extensions::ExtensionMessageBubbleController> controller = - ExtensionMessageBubbleFactory(browser_->profile()).GetController(); - if (controller) { - controller->HighlightExtensionsIfNecessary(); - delegate_->ShowExtensionMessageBubble(controller.Pass()); - } -} - void ToolbarActionsBar::OnToolbarExtensionAdded( const extensions::Extension* extension, int index) {
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar.h b/chrome/browser/ui/toolbar/toolbar_actions_bar.h index 11a8902..3a6798f 100644 --- a/chrome/browser/ui/toolbar/toolbar_actions_bar.h +++ b/chrome/browser/ui/toolbar/toolbar_actions_bar.h
@@ -198,9 +198,6 @@ // Sets |overflowed_action_wants_to_run_| to the proper value. void SetOverflowedActionWantsToRun(); - // Shows an extension message bubble, if any should be shown. - void MaybeShowExtensionBubble(); - bool in_overflow_mode() const { return main_bar_ != nullptr; } // The delegate for this object (in a real build, this is the view). @@ -250,10 +247,6 @@ // True if an action in the overflow menu wants to run. bool overflowed_action_wants_to_run_; - // True if we have checked to see if there is an extension bubble that should - // be displayed, and, if there is, shown that bubble. - bool checked_extension_bubble_; - DISALLOW_COPY_AND_ASSIGN(ToolbarActionsBar); };
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar_delegate.h b/chrome/browser/ui/toolbar/toolbar_actions_bar_delegate.h index af71316..9a24e6d 100644 --- a/chrome/browser/ui/toolbar/toolbar_actions_bar_delegate.h +++ b/chrome/browser/ui/toolbar/toolbar_actions_bar_delegate.h
@@ -5,16 +5,11 @@ #ifndef CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_ACTIONS_BAR_DELEGATE_H_ #define CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_ACTIONS_BAR_DELEGATE_H_ -#include "base/memory/scoped_ptr.h" #include "ui/gfx/animation/tween.h" #include "ui/gfx/geometry/size.h" class ToolbarActionViewController; -namespace extensions { -class ExtensionMessageBubbleController; -} - // The delegate class (which, in production, represents the view) of the // ToolbarActionsBar. class ToolbarActionsBarDelegate { @@ -64,10 +59,6 @@ // action wants to run has changed. virtual void OnOverflowedActionWantsToRunChanged( bool overflowed_action_wants_to_run) = 0; - - // Displays the bubble for the passed ExtensionMessageBubbleController. - virtual void ShowExtensionMessageBubble( - scoped_ptr<extensions::ExtensionMessageBubbleController> controller) = 0; }; #endif // CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_ACTIONS_BAR_DELEGATE_H_
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 a2b70d47..578d693 100644 --- a/chrome/browser/ui/views/extensions/extension_message_bubble_view.cc +++ b/chrome/browser/ui/views/extensions/extension_message_bubble_view.cc
@@ -7,9 +7,24 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "chrome/browser/extensions/dev_mode_bubble_controller.h" +#include "chrome/browser/extensions/extension_action_manager.h" #include "chrome/browser/extensions/extension_message_bubble_controller.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/extension_toolbar_model.h" +#include "chrome/browser/extensions/proxy_overridden_bubble_controller.h" +#include "chrome/browser/extensions/settings_api_bubble_controller.h" +#include "chrome/browser/extensions/settings_api_helpers.h" +#include "chrome/browser/extensions/suspicious_extension_bubble_controller.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/view_ids.h" +#include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/views/toolbar/browser_actions_container.h" +#include "chrome/browser/ui/views/toolbar/browser_actions_container_observer.h" +#include "chrome/browser/ui/views/toolbar/toolbar_view.h" #include "chrome/grit/locale_settings.h" +#include "extensions/browser/extension_prefs.h" +#include "extensions/browser/extension_system.h" #include "ui/accessibility/ax_view_state.h" #include "ui/base/resource/resource_bundle.h" #include "ui/views/controls/button/label_button.h" @@ -21,6 +36,9 @@ namespace { +base::LazyInstance<std::set<Profile*> > g_profiles_evaluated = + LAZY_INSTANCE_INITIALIZER; + // Layout constants. const int kExtensionListPadding = 10; const int kInsetBottomRight = 13; @@ -61,6 +79,21 @@ set_anchor_view_insets(gfx::Insets(5, 0, 5, 0)); } +void ExtensionMessageBubbleView::OnActionButtonClicked( + const base::Closure& callback) { + action_callback_ = callback; +} + +void ExtensionMessageBubbleView::OnDismissButtonClicked( + const base::Closure& callback) { + dismiss_callback_ = callback; +} + +void ExtensionMessageBubbleView::OnLinkClicked( + const base::Closure& callback) { + link_callback_ = callback; +} + void ExtensionMessageBubbleView::Show() { // Not showing the bubble right away (during startup) has a few benefits: // We don't have to worry about focus being lost due to the Omnibox (or to @@ -81,7 +114,7 @@ // To catch Esc, we monitor destroy message. Unless the link has been clicked, // we assume Dismiss was the action taken. if (!link_clicked_ && !action_taken_) - controller_->OnBubbleDismiss(); + dismiss_callback_.Run(); } //////////////////////////////////////////////////////////////////////////////// @@ -208,7 +241,7 @@ const ui::Event& event) { if (sender == action_button_) { action_taken_ = true; - controller_->OnBubbleAction(); + action_callback_.Run(); } else { DCHECK_EQ(dismiss_button_, sender); } @@ -219,7 +252,7 @@ int event_flags) { DCHECK_EQ(learn_more_, source); link_clicked_ = true; - controller_->OnLinkClicked(); + link_callback_.Run(); GetWidget()->Close(); } @@ -234,4 +267,243 @@ NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true); } +//////////////////////////////////////////////////////////////////////////////// +// ExtensionMessageBubbleFactory + +ExtensionMessageBubbleFactory::ExtensionMessageBubbleFactory( + Profile* profile, + ToolbarView* toolbar_view) + : profile_(profile), + toolbar_view_(toolbar_view), + shown_suspicious_extensions_bubble_(false), + shown_startup_override_extensions_bubble_(false), + shown_proxy_override_extensions_bubble_(false), + shown_dev_mode_extensions_bubble_(false), + is_observing_(false), + stage_(STAGE_START), + container_(NULL), + anchor_view_(NULL) {} + +ExtensionMessageBubbleFactory::~ExtensionMessageBubbleFactory() { + MaybeStopObserving(); +} + +void ExtensionMessageBubbleFactory::MaybeShow(views::View* anchor_view) { +#if defined(OS_WIN) + bool is_initial_check = IsInitialProfileCheck(profile_->GetOriginalProfile()); + RecordProfileCheck(profile_->GetOriginalProfile()); + + // The list of suspicious extensions takes priority over the dev mode bubble + // and the settings API bubble, since that needs to be shown as soon as we + // disable something. The settings API bubble is shown on first startup after + // an extension has changed the startup pages and it is acceptable if that + // waits until the next startup because of the suspicious extension bubble. + // The dev mode bubble is not time sensitive like the other two so we'll catch + // the dev mode extensions on the next startup/next window that opens. That + // way, we're not too spammy with the bubbles. + if (!shown_suspicious_extensions_bubble_ && + MaybeShowSuspiciousExtensionsBubble(anchor_view)) + return; + + if (!shown_startup_override_extensions_bubble_ && + is_initial_check && + MaybeShowStartupOverrideExtensionsBubble(anchor_view)) + return; + + if (!shown_proxy_override_extensions_bubble_ && + MaybeShowProxyOverrideExtensionsBubble(anchor_view)) + return; + + if (!shown_dev_mode_extensions_bubble_) + MaybeShowDevModeExtensionsBubble(anchor_view); +#endif // OS_WIN +} + +bool ExtensionMessageBubbleFactory::MaybeShowSuspiciousExtensionsBubble( + views::View* anchor_view) { + DCHECK(!shown_suspicious_extensions_bubble_); + + scoped_ptr<SuspiciousExtensionBubbleController> suspicious_extensions( + new SuspiciousExtensionBubbleController(profile_)); + if (!suspicious_extensions->ShouldShow()) + return false; + + shown_suspicious_extensions_bubble_ = true; + SuspiciousExtensionBubbleController* weak_controller = + suspicious_extensions.get(); + ExtensionMessageBubbleView* bubble_delegate = + new ExtensionMessageBubbleView(anchor_view, + views::BubbleBorder::TOP_RIGHT, + suspicious_extensions.Pass()); + + views::BubbleDelegateView::CreateBubble(bubble_delegate); + weak_controller->Show(bubble_delegate); + + return true; +} + +bool ExtensionMessageBubbleFactory::MaybeShowStartupOverrideExtensionsBubble( + views::View* anchor_view) { +#if !defined(OS_WIN) + return false; +#else + DCHECK(!shown_startup_override_extensions_bubble_); + + const Extension* extension = GetExtensionOverridingStartupPages(profile_); + if (!extension) + return false; + + scoped_ptr<SettingsApiBubbleController> settings_api_bubble( + new SettingsApiBubbleController(profile_, + BUBBLE_TYPE_STARTUP_PAGES)); + if (!settings_api_bubble->ShouldShow(extension->id())) + return false; + + shown_startup_override_extensions_bubble_ = true; + PrepareToHighlightExtensions(settings_api_bubble.Pass(), anchor_view); + return true; +#endif +} + +bool ExtensionMessageBubbleFactory::MaybeShowProxyOverrideExtensionsBubble( + views::View* anchor_view) { +#if !defined(OS_WIN) + return false; +#else + DCHECK(!shown_proxy_override_extensions_bubble_); + + const Extension* extension = GetExtensionOverridingProxy(profile_); + if (!extension) + return false; + + scoped_ptr<ProxyOverriddenBubbleController> proxy_bubble( + new ProxyOverriddenBubbleController(profile_)); + if (!proxy_bubble->ShouldShow(extension->id())) + return false; + + shown_proxy_override_extensions_bubble_ = true; + PrepareToHighlightExtensions(proxy_bubble.Pass(), anchor_view); + return true; +#endif +} + +bool ExtensionMessageBubbleFactory::MaybeShowDevModeExtensionsBubble( + views::View* anchor_view) { + DCHECK(!shown_dev_mode_extensions_bubble_); + + // Check the Developer Mode extensions. + scoped_ptr<DevModeBubbleController> dev_mode_extensions( + new DevModeBubbleController(profile_)); + + // Return early if we have none to show. + if (!dev_mode_extensions->ShouldShow()) + return false; + + shown_dev_mode_extensions_bubble_ = true; + PrepareToHighlightExtensions(dev_mode_extensions.Pass(), anchor_view); + return true; +} + +void ExtensionMessageBubbleFactory::MaybeObserve() { + if (!is_observing_) { + is_observing_ = true; + container_->AddObserver(this); + } +} + +void ExtensionMessageBubbleFactory::MaybeStopObserving() { + if (is_observing_) { + is_observing_ = false; + container_->RemoveObserver(this); + } +} + +void ExtensionMessageBubbleFactory::RecordProfileCheck(Profile* profile) { + g_profiles_evaluated.Get().insert(profile); +} + +bool ExtensionMessageBubbleFactory::IsInitialProfileCheck(Profile* profile) { + return g_profiles_evaluated.Get().count(profile) == 0; +} + +void ExtensionMessageBubbleFactory::OnBrowserActionsContainerAnimationEnded() { + MaybeStopObserving(); + if (stage_ == STAGE_START) { + HighlightExtensions(); + } else if (stage_ == STAGE_HIGHLIGHTED) { + ShowHighlightingBubble(); + } else { // We shouldn't be observing if we've completed the process. + NOTREACHED(); + Finish(); + } +} + +void ExtensionMessageBubbleFactory::OnBrowserActionsContainerDestroyed() { + // If the container associated with the bubble is destroyed, abandon the + // process. + Finish(); +} + +void ExtensionMessageBubbleFactory::PrepareToHighlightExtensions( + scoped_ptr<ExtensionMessageBubbleController> controller, + views::View* anchor_view) { + // We should be in the start stage (i.e., should not have a pending attempt to + // show a bubble). + DCHECK_EQ(stage_, STAGE_START); + + // Prepare to display and highlight the extensions before showing the bubble. + // Since this is an asynchronous process, set member variables for later use. + controller_ = controller.Pass(); + anchor_view_ = anchor_view; + container_ = toolbar_view_->browser_actions(); + + if (container_->animating()) + MaybeObserve(); + else + HighlightExtensions(); +} + +void ExtensionMessageBubbleFactory::HighlightExtensions() { + DCHECK_EQ(STAGE_START, stage_); + stage_ = STAGE_HIGHLIGHTED; + + const ExtensionIdList extension_list = controller_->GetExtensionIdList(); + DCHECK(!extension_list.empty()); + ExtensionToolbarModel::Get(profile_)->HighlightExtensions(extension_list); + if (container_->animating()) + MaybeObserve(); + else + ShowHighlightingBubble(); +} + +void ExtensionMessageBubbleFactory::ShowHighlightingBubble() { + DCHECK_EQ(stage_, STAGE_HIGHLIGHTED); + stage_ = STAGE_COMPLETE; + + views::View* reference_view = NULL; + if (container_->num_toolbar_actions() > 0u) + reference_view = container_->GetToolbarActionViewAt(0); + if (reference_view && reference_view->visible()) + anchor_view_ = reference_view; + + ExtensionMessageBubbleController* weak_controller = controller_.get(); + ExtensionMessageBubbleView* bubble_delegate = + new ExtensionMessageBubbleView( + anchor_view_, + views::BubbleBorder::TOP_RIGHT, + scoped_ptr<ExtensionMessageBubbleController>( + controller_.release())); + views::BubbleDelegateView::CreateBubble(bubble_delegate); + weak_controller->Show(bubble_delegate); + + Finish(); +} + +void ExtensionMessageBubbleFactory::Finish() { + MaybeStopObserving(); + controller_.reset(); + anchor_view_ = NULL; + container_ = NULL; +} + } // namespace extensions
diff --git a/chrome/browser/ui/views/extensions/extension_message_bubble_view.h b/chrome/browser/ui/views/extensions/extension_message_bubble_view.h index 177673f..eadaf716 100644 --- a/chrome/browser/ui/views/extensions/extension_message_bubble_view.h +++ b/chrome/browser/ui/views/extensions/extension_message_bubble_view.h
@@ -5,14 +5,18 @@ #ifndef CHROME_BROWSER_UI_VIEWS_EXTENSIONS_EXTENSION_MESSAGE_BUBBLE_VIEW_H_ #define CHROME_BROWSER_UI_VIEWS_EXTENSIONS_EXTENSION_MESSAGE_BUBBLE_VIEW_H_ +#include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "chrome/browser/extensions/extension_message_bubble.h" +#include "chrome/browser/ui/views/toolbar/browser_actions_container_observer.h" #include "ui/views/bubble/bubble_delegate.h" #include "ui/views/controls/button/button.h" #include "ui/views/controls/link_listener.h" class Profile; +class BrowserActionsContainer; +class ToolbarView; namespace views { class Label; @@ -22,8 +26,121 @@ namespace extensions { +class DevModeBubbleController; class ExtensionMessageBubbleController; +// Create and show ExtensionMessageBubbles for either extensions that look +// suspicious and have therefore been disabled, or for extensions that are +// running in developer mode that we want to warn the user about. +// Calling MaybeShow() will show one of the bubbles, if there is cause to (we +// don't show both in order to avoid spamminess). The suspicious extensions +// bubble takes priority over the developer mode extensions bubble. +class ExtensionMessageBubbleFactory : public BrowserActionsContainerObserver { + public: + ExtensionMessageBubbleFactory(Profile* profile, ToolbarView* toolbar_view); + ~ExtensionMessageBubbleFactory() override; + + void MaybeShow(views::View* anchor_view); + + private: + // The stage of showing the developer mode extensions bubble. STAGE_START + // corresponds to the beginning of the process, when nothing has been done. + // STAGE_HIGHLIGHTED indicates that the toolbar should be highlighting + // dangerous extensions. STAGE_COMPLETE means that the process should be + // ended. + enum Stage { STAGE_START, STAGE_HIGHLIGHTED, STAGE_COMPLETE }; + + // Shows the suspicious extensions bubble, if there are suspicious extensions + // and we have not done so already. + // Returns true if we have show the view. + bool MaybeShowSuspiciousExtensionsBubble(views::View* anchor_view); + + // Shows the settings API extensions bubble, if there are extensions + // overriding the startup pages and we have not done so already. + // Returns true if we show the view (or start the process). + bool MaybeShowStartupOverrideExtensionsBubble(views::View* anchor_view); + + // Shows the bubble for when there are extensions overriding the proxy (if we + // have not done so already). Returns true if we show the view (or start the + // process of doing so). + bool MaybeShowProxyOverrideExtensionsBubble(views::View* anchor_view); + + // Shows the developer mode extensions bubble, if there are extensions running + // in developer mode and we have not done so already. + // Returns true if we show the view (or start the process). + bool MaybeShowDevModeExtensionsBubble(views::View* anchor_view); + + // Starts or stops observing the BrowserActionsContainer, if necessary. + void MaybeObserve(); + void MaybeStopObserving(); + + // Adds |profile| to the list of profiles that have been evaluated for showing + // a bubble. Handy for things that only want to check once per profile. + void RecordProfileCheck(Profile* profile); + // Returns false if this profile has been evaluated before. + bool IsInitialProfileCheck(Profile* profile); + + // BrowserActionsContainer::Observer implementation. + void OnBrowserActionsContainerAnimationEnded() override; + void OnBrowserActionsContainerDestroyed() override; + + // Sets the stage for highlighting extensions and then showing the bubble + // controlled by |controller|, anchored to |anchor_view|. + void PrepareToHighlightExtensions( + scoped_ptr<ExtensionMessageBubbleController> controller, + views::View* anchor_view); + + // Inform the ExtensionToolbarModel to highlight the appropriate extensions. + void HighlightExtensions(); + + // Shows the waiting bubbble, after highlighting the extensions. + void ShowHighlightingBubble(); + + // Finishes the process of showing the developer mode bubble. + void Finish(); + + // The associated profile. + Profile* profile_; + + // The toolbar view that the ExtensionMessageBubbleViews will attach to. + ToolbarView* toolbar_view_; + + // Whether or not we have shown the suspicious extensions bubble. + bool shown_suspicious_extensions_bubble_; + + // Whether or not we have shown the Settings API extensions bubble notifying + // the user about the startup pages being overridden. + bool shown_startup_override_extensions_bubble_; + + // Whether or not we have shown the bubble notifying the user about the proxy + // being overridden. + bool shown_proxy_override_extensions_bubble_; + + // Whether or not we have shown the developer mode extensions bubble. + bool shown_dev_mode_extensions_bubble_; + + // Whether or not we are already observing the BrowserActionsContainer (so + // we don't add ourselves twice). + bool is_observing_; + + // The current stage of showing the bubble. + Stage stage_; + + // The BrowserActionsContainer for the profile. This will be NULL if the + // factory is not currently in the process of showing a bubble. + BrowserActionsContainer* container_; + + // The default view to anchor the bubble to. This will be NULL if the factory + // is not currently in the process of showing a bubble. + views::View* anchor_view_; + + // The controller to show a bubble for. This will be NULL if the factory is + // not currently in the process of showing a bubble. + scoped_ptr<ExtensionMessageBubbleController> controller_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionMessageBubbleFactory); +}; + // This is a class that implements the UI for the bubble showing which // extensions look suspicious and have therefore been automatically disabled. class ExtensionMessageBubbleView : public ExtensionMessageBubble, @@ -37,6 +154,9 @@ scoped_ptr<ExtensionMessageBubbleController> controller); // ExtensionMessageBubble methods. + void OnActionButtonClicked(const base::Closure& callback) override; + void OnDismissButtonClicked(const base::Closure& callback) override; + void OnLinkClicked(const base::Closure& callback) override; void Show() override; // WidgetObserver methods. @@ -78,6 +198,11 @@ bool link_clicked_; bool action_taken_; + // Callbacks into the controller. + base::Closure action_callback_; + base::Closure dismiss_callback_; + base::Closure link_callback_; + base::WeakPtrFactory<ExtensionMessageBubbleView> weak_factory_; DISALLOW_COPY_AND_ASSIGN(ExtensionMessageBubbleView);
diff --git a/chrome/browser/ui/views/settings_api_bubble_helper_views.cc b/chrome/browser/ui/views/settings_api_bubble_helper_views.cc index 06bb439..341dc6124 100644 --- a/chrome/browser/ui/views/settings_api_bubble_helper_views.cc +++ b/chrome/browser/ui/views/settings_api_bubble_helper_views.cc
@@ -25,12 +25,13 @@ namespace { void ShowSettingsApiBubble(SettingsApiOverrideType type, + const std::string& extension_id, Profile* profile, views::View* anchor_view, views::BubbleBorder::Arrow arrow) { scoped_ptr<SettingsApiBubbleController> settings_api_bubble( new SettingsApiBubbleController(profile, type)); - if (!settings_api_bubble->ShouldShow()) + if (!settings_api_bubble->ShouldShow(extension_id)) return; SettingsApiBubbleController* controller = settings_api_bubble.get(); @@ -47,13 +48,18 @@ return; #endif - // The bubble will try to anchor itself against the home button - views::View* anchor_view = BrowserView::GetBrowserViewForBrowser(browser)-> - toolbar()->home_button(); - ShowSettingsApiBubble(BUBBLE_TYPE_HOME_PAGE, - browser->profile(), - anchor_view, - views::BubbleBorder::TOP_LEFT); + const Extension* extension = + GetExtensionOverridingHomepage(browser->profile()); + if (extension) { + // The bubble will try to anchor itself against the home button + views::View* anchor_view = BrowserView::GetBrowserViewForBrowser(browser)-> + toolbar()->home_button(); + ShowSettingsApiBubble(BUBBLE_TYPE_HOME_PAGE, + extension->id(), + browser->profile(), + anchor_view, + views::BubbleBorder::TOP_LEFT); + } } void MaybeShowExtensionControlledSearchNotification( @@ -66,13 +72,17 @@ if (AutocompleteMatch::IsSearchType(match.type) && match.type != AutocompleteMatchType::SEARCH_OTHER_ENGINE) { - ToolbarView* toolbar = - BrowserView::GetBrowserViewForBrowser( - chrome::FindBrowserWithWebContents(web_contents))->toolbar(); - ShowSettingsApiBubble(BUBBLE_TYPE_SEARCH_ENGINE, - profile, - toolbar->app_menu(), - views::BubbleBorder::TOP_RIGHT); + const Extension* extension = GetExtensionOverridingSearchEngine(profile); + if (extension) { + ToolbarView* toolbar = + BrowserView::GetBrowserViewForBrowser( + chrome::FindBrowserWithWebContents(web_contents))->toolbar(); + ShowSettingsApiBubble(BUBBLE_TYPE_SEARCH_ENGINE, + extension->id(), + profile, + toolbar->app_menu(), + views::BubbleBorder::TOP_RIGHT); + } } }
diff --git a/chrome/browser/ui/views/toolbar/browser_actions_container.cc b/chrome/browser/ui/views/toolbar/browser_actions_container.cc index 84deb1a9..b86b084 100644 --- a/chrome/browser/ui/views/toolbar/browser_actions_container.cc +++ b/chrome/browser/ui/views/toolbar/browser_actions_container.cc
@@ -6,7 +6,6 @@ #include "base/compiler_specific.h" #include "base/stl_util.h" -#include "chrome/browser/extensions/extension_message_bubble_controller.h" #include "chrome/browser/extensions/tab_helper.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" @@ -15,7 +14,6 @@ #include "chrome/browser/ui/toolbar/toolbar_actions_bar.h" #include "chrome/browser/ui/view_ids.h" #include "chrome/browser/ui/views/extensions/browser_action_drag_data.h" -#include "chrome/browser/ui/views/extensions/extension_message_bubble_view.h" #include "chrome/browser/ui/views/extensions/extension_toolbar_icon_surfacing_bubble_views.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/toolbar/browser_actions_container_observer.h" @@ -341,30 +339,6 @@ overflowed_action_wants_to_run); } -void BrowserActionsContainer::ShowExtensionMessageBubble( - scoped_ptr<extensions::ExtensionMessageBubbleController> controller) { - if (animating()) { - // If the container is animating, we can't effectively anchor the bubble, - // so wait until animation stops. - pending_extension_bubble_controller_ = controller.Pass(); - return; - } - - views::View* reference_view = VisibleBrowserActions() > 0 ? - static_cast<views::View*>(toolbar_action_views_[0]) : - BrowserView::GetBrowserViewForBrowser(browser_)->toolbar()->app_menu(); - - extensions::ExtensionMessageBubbleController* weak_controller = - controller.get(); - extensions::ExtensionMessageBubbleView* bubble = - new extensions::ExtensionMessageBubbleView( - reference_view, - views::BubbleBorder::TOP_RIGHT, - controller.Pass()); - views::BubbleDelegateView::CreateBubble(bubble); - weak_controller->Show(bubble); -} - void BrowserActionsContainer::AddObserver( BrowserActionsContainerObserver* observer) { observers_.AddObserver(observer); @@ -694,9 +668,6 @@ FOR_EACH_OBSERVER(BrowserActionsContainerObserver, observers_, OnBrowserActionsContainerAnimationEnded()); - - if (pending_extension_bubble_controller_) - ShowExtensionMessageBubble(pending_extension_bubble_controller_.Pass()); } content::WebContents* BrowserActionsContainer::GetCurrentWebContents() {
diff --git a/chrome/browser/ui/views/toolbar/browser_actions_container.h b/chrome/browser/ui/views/toolbar/browser_actions_container.h index 3b26802..ab40e10 100644 --- a/chrome/browser/ui/views/toolbar/browser_actions_container.h +++ b/chrome/browser/ui/views/toolbar/browser_actions_container.h
@@ -252,9 +252,6 @@ bool IsPopupRunning() const override; void OnOverflowedActionWantsToRunChanged( bool overflowed_action_wants_to_run) override; - void ShowExtensionMessageBubble( - scoped_ptr<extensions::ExtensionMessageBubbleController> controller) - override; // Overridden from extension::ExtensionKeybindingRegistry::Delegate: extensions::ActiveTabPermissionGranter* GetActiveTabPermissionGranter() @@ -345,10 +342,6 @@ // The class that registers for keyboard shortcuts for extension commands. scoped_ptr<ExtensionKeybindingRegistryViews> extension_keybinding_registry_; - // The controller of the bubble to show once animation finishes, if any. - scoped_ptr<extensions::ExtensionMessageBubbleController> - pending_extension_bubble_controller_; - ObserverList<BrowserActionsContainerObserver> observers_; DISALLOW_COPY_AND_ASSIGN(BrowserActionsContainer);
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc index df70ca44a..7c4073b 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -31,6 +31,7 @@ #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/toolbar/wrench_menu_model.h" #include "chrome/browser/ui/view_ids.h" +#include "chrome/browser/ui/views/extensions/extension_message_bubble_view.h" #include "chrome/browser/ui/views/extensions/extension_popup.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/location_bar/page_action_image_view.h" @@ -129,7 +130,10 @@ browser_actions_(NULL), app_menu_(NULL), browser_(browser), - badge_controller_(browser->profile(), this) { + badge_controller_(browser->profile(), this), + extension_message_bubble_factory_( + new extensions::ExtensionMessageBubbleFactory(browser->profile(), + this)) { set_id(VIEW_ID_TOOLBAR); SetEventTargeter( @@ -267,6 +271,14 @@ } } +void ToolbarView::OnWidgetVisibilityChanged(views::Widget* widget, + bool visible) { + if (visible) { + // Safe to call multiple times; the bubble will only appear once. + extension_message_bubble_factory_->MaybeShow(app_menu_); + } +} + void ToolbarView::OnWidgetActivationChanged(views::Widget* widget, bool active) { extensions::ExtensionCommandsGlobalRegistry* registry =
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.h b/chrome/browser/ui/views/toolbar/toolbar_view.h index 0e60a16..32fe3f6 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view.h +++ b/chrome/browser/ui/views/toolbar/toolbar_view.h
@@ -31,6 +31,7 @@ namespace extensions { class Command; class Extension; +class ExtensionMessageBubbleFactory; } namespace views { @@ -136,6 +137,7 @@ void ButtonPressed(views::Button* sender, const ui::Event& event) override; // views::WidgetObserver: + void OnWidgetVisibilityChanged(views::Widget* widget, bool visible) override; void OnWidgetActivationChanged(views::Widget* widget, bool active) override; // content::NotificationObserver: @@ -243,6 +245,11 @@ scoped_ptr<WrenchMenuModel> wrench_menu_model_; scoped_ptr<WrenchMenu> wrench_menu_; + // The factory to create bubbles to warn about dangerous/suspicious + // extensions. + scoped_ptr<extensions::ExtensionMessageBubbleFactory> + extension_message_bubble_factory_; + // A list of listeners to call when the menu opens. ObserverList<views::MenuListener> menu_listeners_;
diff --git a/chrome/browser/ui/webui/large_icon_source.cc b/chrome/browser/ui/webui/large_icon_source.cc index 56e34613..df1e285f 100644 --- a/chrome/browser/ui/webui/large_icon_source.cc +++ b/chrome/browser/ui/webui/large_icon_source.cc
@@ -4,8 +4,6 @@ #include "chrome/browser/ui/webui/large_icon_source.h" -#include <vector> - #include "base/memory/ref_counted_memory.h" #include "chrome/browser/search/instant_io_context.h" #include "chrome/common/favicon/large_icon_url_parser.h" @@ -15,11 +13,18 @@ #include "components/favicon_base/fallback_icon_style.h" #include "net/url_request/url_request.h" #include "third_party/skia/include/core/SkColor.h" +#include "ui/gfx/color_analysis.h" +#include "ui/gfx/color_utils.h" namespace { -int kDefaultLargeIconSize = 96; -int kMaxLargeIconSize = 192; // Arbitrary bound to safeguard endpoint. +const int kDefaultLargeIconSize = 96; +const int kMaxLargeIconSize = 192; // Arbitrary bound to safeguard endpoint. + +const double kMaxBackgroundLuminance = 0.67; +const SkColor kDarkGray = SkColorSetRGB(0x78, 0x78, 0x78); +const SkColor kTextColor = SK_ColorWHITE; +const SkColor kDefaultBackgroundColor = kDarkGray; } // namespace @@ -43,6 +48,9 @@ favicon::FallbackIconService* fallback_icon_service) : favicon_service_(favicon_service), fallback_icon_service_(fallback_icon_service) { + large_icon_types_.push_back(favicon_base::IconType::FAVICON); + large_icon_types_.push_back(favicon_base::IconType::TOUCH_ICON); + large_icon_types_.push_back(favicon_base::IconType::TOUCH_PRECOMPOSED_ICON); } LargeIconSource::~LargeIconSource() { @@ -77,9 +85,9 @@ return; } - favicon_service_->GetRawFaviconForPageURL( + favicon_service_->GetLargestRawFaviconForPageURL( url, - favicon_base::TOUCH_ICON | favicon_base::TOUCH_PRECOMPOSED_ICON, + large_icon_types_, parser.size_in_pixels(), base::Bind( &LargeIconSource::OnIconDataAvailable, @@ -110,20 +118,45 @@ void LargeIconSource::OnIconDataAvailable( const IconRequest& request, const favicon_base::FaviconRawBitmapResult& bitmap_result) { - if (!bitmap_result.is_valid()) - SendFallbackIcon(request); - else - request.callback.Run(bitmap_result.bitmap_data.get()); + if (!bitmap_result.is_valid()) { + SendDefaultFallbackIcon(request); + return; + } + + // If we found a bitmap, but it's smaller than the requested size, we + // generate a fallback using the dominant color from the too-small bitmap. + // We adjust the luminance of the background so we can put light text over it. + if (bitmap_result.pixel_size.width() < request.size || + bitmap_result.pixel_size.height() < request.size) { + SkColor background = + color_utils::CalculateKMeanColorOfPNG(bitmap_result.bitmap_data); + color_utils::HSL background_hsl; + color_utils::SkColorToHSL(background, &background_hsl); + background_hsl.l = std::min(background_hsl.l, kMaxBackgroundLuminance); + background = color_utils::HSLToSkColor(background_hsl, SK_AlphaOPAQUE); + + // Now we can construct the fallback icon. + SendFallbackIcon(request, kTextColor, background); + return; + } + + request.callback.Run(bitmap_result.bitmap_data.get()); } -void LargeIconSource::SendFallbackIcon(const IconRequest& request) { +void LargeIconSource::SendDefaultFallbackIcon(const IconRequest& request) { + SendFallbackIcon(request, kTextColor, kDefaultBackgroundColor); +} + +void LargeIconSource::SendFallbackIcon(const IconRequest& request, + SkColor text_color, + SkColor background_color) { if (!fallback_icon_service_) { SendNotFoundResponse(request.callback); return; } favicon_base::FallbackIconStyle style; - style.background_color = SkColorSetRGB(0x78, 0x78, 0x78); - style.text_color = SK_ColorWHITE; + style.background_color = background_color; + style.text_color = text_color; style.font_size_ratio = 0.44; style.roundness = 0; // Square. Round corners can be applied by JavaScript. std::vector<unsigned char> bitmap_data =
diff --git a/chrome/browser/ui/webui/large_icon_source.h b/chrome/browser/ui/webui/large_icon_source.h index 7557cfd..05872d2 100644 --- a/chrome/browser/ui/webui/large_icon_source.h +++ b/chrome/browser/ui/webui/large_icon_source.h
@@ -6,12 +6,14 @@ #define CHROME_BROWSER_UI_WEBUI_LARGE_ICON_SOURCE_H_ #include <string> +#include <vector> #include "base/memory/scoped_ptr.h" #include "base/task/cancelable_task_tracker.h" #include "components/favicon/core/fallback_icon_service.h" #include "components/favicon_base/favicon_types.h" #include "content/public/browser/url_data_source.h" +#include "third_party/skia/include/core/SkColor.h" namespace favicon { class FallbackIconService; @@ -70,8 +72,15 @@ const IconRequest& request, const favicon_base::FaviconRawBitmapResult& bitmap_result); - // Renders and sends a fallback icon. - void SendFallbackIcon(const IconRequest& request); + // Renders and sends a default fallback icon. This is used when there is no + // known text and/or foreground color to use for the generated icon (it + // defaults to a light text color on a dark gray background). + void SendDefaultFallbackIcon(const IconRequest& request); + + // Renders and sends a fallback icon using the given colors. + void SendFallbackIcon(const IconRequest& request, + SkColor text_color, + SkColor background_color); // Returns null to trigger "Not Found" response. void SendNotFoundResponse( @@ -83,6 +92,12 @@ favicon::FallbackIconService* fallback_icon_service_; + // A pre-populated list of the types of icon files to consider when looking + // for the largest matching icon. + // Note: this is simply an optimization over populating an icon type vector + // on each request. + std::vector<int> large_icon_types_; + DISALLOW_COPY_AND_ASSIGN(LargeIconSource); };
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc index 9bcb16b4c..7a2b2c7 100644 --- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -85,6 +85,13 @@ IDS_SETTINGS_DOWNLOADS_PROMPT_FOR_DOWNLOAD_LABEL); } +#if defined(OS_CHROMEOS) +void AddInternetStrings(content::WebUIDataSource* html_source) { + html_source->AddLocalizedString( + "internetPageTitle", IDS_SETTINGS_INTERNET_PAGE_TITLE); +} +#endif + } // namespace namespace settings { @@ -92,7 +99,9 @@ void AddLocalizedStrings(content::WebUIDataSource* html_source) { AddA11yStrings(html_source); AddDownloadsStrings(html_source); - +#if defined(OS_CHROMEOS) + AddInternetStrings(html_source); +#endif html_source->SetJsonPath(kLocalizedStringsFile); }
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index c5eff40..6a254de06 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi
@@ -20,6 +20,8 @@ 'chrome_browser_non_ios_sources': [ 'browser/about_flags.cc', 'browser/about_flags.h', + 'browser/after_startup_task_utils.cc', + 'browser/after_startup_task_utils.h', 'browser/android/accessibility/font_size_prefs_android.cc', 'browser/android/accessibility/font_size_prefs_android.h', 'browser/android/accessibility_util.cc', @@ -304,6 +306,8 @@ 'browser/component_updater/sw_reporter_installer_win.h', 'browser/component_updater/swiftshader_component_installer.cc', 'browser/component_updater/swiftshader_component_installer.h', + 'browser/component_updater/url_constants.cc', + 'browser/component_updater/url_constants.h', 'browser/crash_upload_list.cc', 'browser/crash_upload_list.h', 'browser/crash_upload_list_mac.cc',
diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi index f8dc319..ff08a47 100644 --- a/chrome/chrome_browser_chromeos.gypi +++ b/chrome/chrome_browser_chromeos.gypi
@@ -357,6 +357,8 @@ 'browser/chromeos/fileapi/file_system_backend_delegate.h', 'browser/chromeos/fileapi/mtp_file_system_backend_delegate.cc', 'browser/chromeos/fileapi/mtp_file_system_backend_delegate.h', + 'browser/chromeos/fileapi/mtp_watcher_manager.cc', + 'browser/chromeos/fileapi/mtp_watcher_manager.h', 'browser/chromeos/first_run/drive_first_run_controller.cc', 'browser/chromeos/first_run/drive_first_run_controller.h', 'browser/chromeos/first_run/first_run.cc',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi index fe5259fd..5e6f594 100644 --- a/chrome/chrome_browser_ui.gypi +++ b/chrome/chrome_browser_ui.gypi
@@ -2592,8 +2592,6 @@ 'browser/ui/extensions/extension_action_platform_delegate.h', 'browser/ui/extensions/extension_action_view_controller.cc', 'browser/ui/extensions/extension_action_view_controller.h', - 'browser/ui/extensions/extension_message_bubble_factory.cc', - 'browser/ui/extensions/extension_message_bubble_factory.h', 'browser/ui/extensions/extension_enable_flow.cc', 'browser/ui/extensions/extension_enable_flow.h', 'browser/ui/extensions/extension_enable_flow_delegate.h',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index 427f2c16..e29e7ba 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi
@@ -14,6 +14,7 @@ '../tools/metrics/histograms/histograms.xml', # All unittests in browser, common, renderer and service. 'browser/about_flags_unittest.cc', + 'browser/after_startup_task_utils_unittest.cc', 'browser/android/bookmarks/partner_bookmarks_shim_unittest.cc', # TODO(newt): move this to test_support_unit? 'browser/android/mock_location_settings.cc',
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn index 9465fa4..947666f0 100644 --- a/chrome/common/BUILD.gn +++ b/chrome/common/BUILD.gn
@@ -109,6 +109,9 @@ "//extensions/strings", "//media/cast:net", ] + if (enable_media_router) { + defines += [ "ENABLE_MEDIA_ROUTER=1" ] + } } if (is_win || is_mac) {
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc index 41dfa45..2411fa2a 100644 --- a/chrome/common/extensions/extension_constants.cc +++ b/chrome/common/extensions/extension_constants.cc
@@ -50,6 +50,9 @@ const char kSettingsAppId[] = "ennkphjdgehloodpbhlhldgbnhmacadg"; const char kYoutubeAppId[] = "blpcfgokakmgnkcojhhkbfbldkacnbeo"; const char kInAppPaymentsSupportAppId[] = "nmmhkkegccagdldgiimedpiccmgmieda"; +#if defined(ENABLE_MEDIA_ROUTER) +const char kMediaRouterStableExtensionId[] = "fjhoaacokmgbjemoflkofnenfaiekifl"; +#endif // defined(ENABLE_MEDIA_ROUTER) #if defined(OS_CHROMEOS) // The extension id for the built-in component extension.
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h index b368a7d4..46226be 100644 --- a/chrome/common/extensions/extension_constants.h +++ b/chrome/common/extensions/extension_constants.h
@@ -94,6 +94,11 @@ // The extension id of the in-app payments support application. extern const char kInAppPaymentsSupportAppId[]; +#if defined(ENABLE_MEDIA_ROUTER) +// The extension id of the stable media router extension. +extern const char kMediaRouterStableExtensionId[]; +#endif // defined(ENABLE_MEDIA_ROUTER) + // The buckets used for app launches. enum AppLaunchBucket { // Launch from NTP apps section while maximized.
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index b8e0e74..2966dbf9 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc
@@ -1619,6 +1619,9 @@ // A dictionary of port->location pairs for port forwarding. const char kDevToolsPortForwardingConfig[] = "devtools.port_forwarding_config"; +// A dictionary with generic DevTools settings. +const char kDevToolsPreferences[] = "devtools.preferences"; + #if defined(OS_ANDROID) // A boolean specifying whether remote dev tools debugging is enabled. const char kDevToolsRemoteEnabled[] = "devtools.remote_enabled";
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 2ebb866..b40b4f0 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -570,6 +570,7 @@ extern const char kDevToolsPortForwardingEnabled[]; extern const char kDevToolsPortForwardingDefaultSet[]; extern const char kDevToolsPortForwardingConfig[]; +extern const char kDevToolsPreferences[]; #if defined(OS_ANDROID) extern const char kDevToolsRemoteEnabled[]; #endif
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 3997dc3..a3361dd 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1673,7 +1673,7 @@ } } - if (is_linux && !is_chromeos) { + if (is_win || (is_linux && !is_chromeos)) { # TODO(GYP): Figure out which of these work and are needed on other # platforms. test("chrome_app_unittests") { @@ -1694,6 +1694,7 @@ deps = [ ":test_support", + "//breakpad:client", "//chrome/browser", "//chrome/child", "//base/test:run_all_unittests",
diff --git a/chrome/test/data/chromeos/wallpaper_manager/unit_tests/api_mock.js b/chrome/test/data/chromeos/wallpaper_manager/unit_tests/api_mock.js index 143e6c33..c7d2b7be 100644 --- a/chrome/test/data/chromeos/wallpaper_manager/unit_tests/api_mock.js +++ b/chrome/test/data/chromeos/wallpaper_manager/unit_tests/api_mock.js
@@ -201,6 +201,8 @@ get: function(key, callback) { var items = {}; switch (key) { + case Constants.AccessLocalSurpriseMeEnabledKey: + items[Constants.AccessLocalSurpriseMeEnabledKey] = true; case Constants.AccessLocalWallpaperInfoKey: items[Constants.AccessLocalWallpaperInfoKey] = { 'url': 'dummy', @@ -217,8 +219,8 @@ get: function(key, callback) { var items = {}; switch (key) { - case Constants.AccessSurpriseMeEnabledKey: - items[Constants.AccessSurpriseMeEnabledKey] = true; + case Constants.AccessSyncSurpriseMeEnabledKey: + items[Constants.AccessSyncSurpriseMeEnabledKey] = true; case Constants.AccessLastSurpriseWallpaperChangedDate: items[Constants.AccessLastSurpriseWallpaperChangedDate] = new Date().toDateString(); @@ -266,7 +268,13 @@ callback) { }, getSyncSetting: function(callback) { - callback({syncThemes: true}); + var setting = {}; + setting.syncThemes = true; + callback(setting); + }, + onWallpaperChangedBy3rdParty: { + addListener: function(listener) { + } } }, runtime: {
diff --git a/chrome/test/data/chromeos/wallpaper_manager/unit_tests/event_page_unittest.js b/chrome/test/data/chromeos/wallpaper_manager/unit_tests/event_page_unittest.js index 34f75cfb..01f7699 100644 --- a/chrome/test/data/chromeos/wallpaper_manager/unit_tests/event_page_unittest.js +++ b/chrome/test/data/chromeos/wallpaper_manager/unit_tests/event_page_unittest.js
@@ -6,7 +6,9 @@ var mockController; WallpaperUtil.enabledSyncThemesCallback = function(callback) { - callback(); + chrome.wallpaperPrivate.getSyncSetting(function(setting) { + callback(setting.syncThemes); + }); }; function setUp() {
diff --git a/chrome/test/data/extensions/api_test/events_are_unregistered/manifest.json b/chrome/test/data/extensions/api_test/events_are_unregistered/manifest.json new file mode 100644 index 0000000..ac97ea6 --- /dev/null +++ b/chrome/test/data/extensions/api_test/events_are_unregistered/manifest.json
@@ -0,0 +1,7 @@ +{ + "browser_action": {}, + "description": "events_are_unregistered", + "manifest_version": 2, + "name": "events_are_unregistered", + "version": "1" +}
diff --git a/chrome/test/data/extensions/api_test/events_are_unregistered/page1.html b/chrome/test/data/extensions/api_test/events_are_unregistered/page1.html new file mode 100644 index 0000000..034c7de --- /dev/null +++ b/chrome/test/data/extensions/api_test/events_are_unregistered/page1.html
@@ -0,0 +1,6 @@ +<!-- + * 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. +--> +<script src="page1.js"></script>
diff --git a/chrome/test/data/extensions/api_test/events_are_unregistered/page1.js b/chrome/test/data/extensions/api_test/events_are_unregistered/page1.js new file mode 100644 index 0000000..c5ea62eb --- /dev/null +++ b/chrome/test/data/extensions/api_test/events_are_unregistered/page1.js
@@ -0,0 +1,24 @@ +// 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. + +// Register for events in 4 configurations, then navigate to page2.html, which +// will notify success and succeed the test on the C++ side. The C++ code +// asserts that the events have been unregistered. + +// A single listener. +chrome.browserAction.onClicked.addListener(function() {}); +// Multiple listeners for the same event. +chrome.runtime.onStartup.addListener(function() {}); +chrome.runtime.onStartup.addListener(function() {}); +// A single listener, which previously had multiple listeners. +chrome.runtime.onSuspend.addListener(function() {}); +chrome.runtime.onSuspend.addListener(function() {}); +chrome.runtime.onSuspend.removeListener(function() {}); +// No listeners, which previously had listeners (all were removed). +chrome.runtime.onInstalled.addListener(function() {}); +chrome.runtime.onInstalled.addListener(function() {}); +chrome.runtime.onInstalled.removeListener(function() {}); +chrome.runtime.onInstalled.removeListener(function() {}); + +location.assign('page2.html');
diff --git a/chrome/test/data/extensions/api_test/events_are_unregistered/page2.html b/chrome/test/data/extensions/api_test/events_are_unregistered/page2.html new file mode 100644 index 0000000..aa09459b --- /dev/null +++ b/chrome/test/data/extensions/api_test/events_are_unregistered/page2.html
@@ -0,0 +1,6 @@ +<!-- + * 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. +--> +<script src="page2.js"></script>
diff --git a/chrome/test/data/extensions/api_test/events_are_unregistered/page2.js b/chrome/test/data/extensions/api_test/events_are_unregistered/page2.js new file mode 100644 index 0000000..26e65df --- /dev/null +++ b/chrome/test/data/extensions/api_test/events_are_unregistered/page2.js
@@ -0,0 +1,6 @@ +// 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. + +// See page1.js to make sense of this. +chrome.test.notifyPass();
diff --git a/chrome/test/data/webui/list_selection_model_test.html b/chrome/test/data/webui/list_selection_model_test.html index f377f7d..58e7e70 100644 --- a/chrome/test/data/webui/list_selection_model_test.html +++ b/chrome/test/data/webui/list_selection_model_test.html
@@ -195,6 +195,35 @@ assertEquals(-1, sm.anchorIndex, 'anchor'); } +function testSelectAll() { + var sm = createSelectionModel(10); + + var changes = null; + sm.addEventListener('change', function(e) { + changes = e.changes; + }); + + sm.selectAll(); + + assertArrayEquals(range(0, 9), sm.selectedIndexes); + assertArrayEquals(range(0, 9), + changes.map(function(change) { return change.index; })); +} + +function testSelectAllOnEmptyList() { + var sm = createSelectionModel(0); + + var changes = null; + sm.addEventListener('change', function(e) { + changes = e.changes; + }); + + sm.selectAll(); + + assertArrayEquals([], sm.selectedIndexes); + assertEquals(null, changes); +} + </script> </body>
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc index c145d9f..3234a59 100644 --- a/chromecast/browser/cast_content_browser_client.cc +++ b/chromecast/browser/cast_content_browser_client.cc
@@ -17,6 +17,7 @@ #include "chromecast/browser/cast_browser_main_parts.h" #include "chromecast/browser/cast_browser_process.h" #include "chromecast/browser/cast_network_delegate.h" +#include "chromecast/browser/cast_quota_permission_context.h" #include "chromecast/browser/cast_resource_dispatcher_host_delegate.h" #include "chromecast/browser/devtools/cast_dev_tools_delegate.h" #include "chromecast/browser/geolocation/cast_access_token_store.h" @@ -197,6 +198,11 @@ return locale.empty() ? "en-US" : locale; } +content::QuotaPermissionContext* +CastContentBrowserClient::CreateQuotaPermissionContext() { + return new CastQuotaPermissionContext(); +} + void CastContentBrowserClient::AllowCertificateError( int render_process_id, int render_view_id,
diff --git a/chromecast/browser/cast_content_browser_client.h b/chromecast/browser/cast_content_browser_client.h index 83134fe..c35bc2ec 100644 --- a/chromecast/browser/cast_content_browser_client.h +++ b/chromecast/browser/cast_content_browser_client.h
@@ -55,6 +55,7 @@ content::WebPreferences* prefs) override; void ResourceDispatcherHostCreated() override; std::string GetApplicationLocale() override; + content::QuotaPermissionContext* CreateQuotaPermissionContext() override; void AllowCertificateError( int render_process_id, int render_view_id,
diff --git a/chromecast/browser/cast_quota_permission_context.cc b/chromecast/browser/cast_quota_permission_context.cc new file mode 100644 index 0000000..e0ca804 --- /dev/null +++ b/chromecast/browser/cast_quota_permission_context.cc
@@ -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. + +#include "chromecast/browser/cast_quota_permission_context.h" + +namespace chromecast { + +CastQuotaPermissionContext::CastQuotaPermissionContext() { +} + +CastQuotaPermissionContext::~CastQuotaPermissionContext() { +} + +void CastQuotaPermissionContext::RequestQuotaPermission( + const content::StorageQuotaParams& params, + int render_process_id, + const PermissionCallback& callback) { + callback.Run( + content::QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_ALLOW); +} + +} // namespace chromecast
diff --git a/chromecast/browser/cast_quota_permission_context.h b/chromecast/browser/cast_quota_permission_context.h new file mode 100644 index 0000000..2dc41861 --- /dev/null +++ b/chromecast/browser/cast_quota_permission_context.h
@@ -0,0 +1,30 @@ +// 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 CHROMECAST_BROWSER_CAST_QUOTA_PERMISSION_CONTEXT_H_ +#define CHROMECAST_BROWSER_CAST_QUOTA_PERMISSION_CONTEXT_H_ + +#include "base/macros.h" +#include "content/public/browser/quota_permission_context.h" + +namespace chromecast { + +class CastQuotaPermissionContext : public content::QuotaPermissionContext { + public: + CastQuotaPermissionContext(); + + // content::QuotaPermissionContext implementation: + void RequestQuotaPermission(const content::StorageQuotaParams& params, + int render_process_id, + const PermissionCallback& callback) override; + + private: + ~CastQuotaPermissionContext() override; + + DISALLOW_COPY_AND_ASSIGN(CastQuotaPermissionContext); +}; + +} // namespace chromecast + +#endif // CHROMECAST_BROWSER_CAST_QUOTA_PERMISSION_CONTEXT_H_
diff --git a/chromecast/chromecast.gyp b/chromecast/chromecast.gyp index fc4dbd52..82d885df 100644 --- a/chromecast/chromecast.gyp +++ b/chromecast/chromecast.gyp
@@ -215,6 +215,8 @@ 'browser/cast_network_delegate.h', 'browser/cast_permission_manager.cc', 'browser/cast_permission_manager.h', + 'browser/cast_quota_permission_context.cc', + 'browser/cast_quota_permission_context.h', 'browser/cast_resource_dispatcher_host_delegate.cc', 'browser/cast_resource_dispatcher_host_delegate.h', 'browser/devtools/cast_dev_tools_delegate.cc',
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 1cab62b..8e6ce9c 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -6969.0.0 \ No newline at end of file +6972.0.0 \ No newline at end of file
diff --git a/components/OWNERS b/components/OWNERS index ae1edd1..b69b99ad 100644 --- a/components/OWNERS +++ b/components/OWNERS
@@ -77,10 +77,9 @@ per-file error_page*=mmenke@chromium.org per-file error_page*=ttuttle@chromium.org +per-file favicon*=pkotwicz@chromium.org per-file favicon*=sky@chromium.org per-file favicon*=stevenjb@chromium.org -# Temporary for the duration of the favicon componentization. -per-file favicon*=sdefresne@chromium.org per-file feedback.gypi=bsimonnet@chromium.org per-file feedback.gypi=zork@chromium.org @@ -177,6 +176,7 @@ per-file pdf.gypi=thestig@chromium.org per-file plugins.gypi=bauerb@chromium.org +per-file plugins.gypi=tommycli@chromium.org per-file precache*=bengr@chromium.org per-file precache*=sclittle@chromium.org
diff --git a/components/autofill.gypi b/components/autofill.gypi index b2209ea..fd5ceaf 100644 --- a/components/autofill.gypi +++ b/components/autofill.gypi
@@ -43,6 +43,8 @@ 'autofill/core/common/autofill_constants.h', 'autofill/core/common/autofill_data_validation.cc', 'autofill/core/common/autofill_data_validation.h', + 'autofill/core/common/autofill_l10n_util.cc', + 'autofill/core/common/autofill_l10n_util.h', 'autofill/core/common/autofill_pref_names.cc', 'autofill/core/common/autofill_pref_names.h', 'autofill/core/common/autofill_switches.cc',
diff --git a/components/autofill/core/browser/autofill_external_delegate.cc b/components/autofill/core/browser/autofill_external_delegate.cc index 021dfc5..1f711c7 100644 --- a/components/autofill/core/browser/autofill_external_delegate.cc +++ b/components/autofill/core/browser/autofill_external_delegate.cc
@@ -263,12 +263,17 @@ manager_->client()->HideAutofillPopup(); } -void AutofillExternalDelegate::RemoveSuggestion(const base::string16& value, +bool AutofillExternalDelegate::RemoveSuggestion(const base::string16& value, int identifier) { if (identifier > 0) - manager_->RemoveAutofillProfileOrCreditCard(identifier); - else + return manager_->RemoveAutofillProfileOrCreditCard(identifier); + + if (identifier == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY) { manager_->RemoveAutocompleteEntry(query_field_.name, value); + return true; + } + + return false; } void AutofillExternalDelegate::DidEndTextFieldEditing() {
diff --git a/components/autofill/core/browser/autofill_external_delegate.h b/components/autofill/core/browser/autofill_external_delegate.h index 8e8c320..1f88ff0 100644 --- a/components/autofill/core/browser/autofill_external_delegate.h +++ b/components/autofill/core/browser/autofill_external_delegate.h
@@ -42,7 +42,7 @@ int identifier) override; void DidAcceptSuggestion(const base::string16& value, int identifier) override; - void RemoveSuggestion(const base::string16& value, int identifier) override; + bool RemoveSuggestion(const base::string16& value, int identifier) override; void ClearPreviewedForm() override; // Records and associates a query_id with web form data. Called
diff --git a/components/autofill/core/browser/autofill_field.cc b/components/autofill/core/browser/autofill_field.cc index 66417f5..e7e5732 100644 --- a/components/autofill/core/browser/autofill_field.cc +++ b/components/autofill/core/browser/autofill_field.cc
@@ -17,6 +17,7 @@ #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/phone_number.h" #include "components/autofill/core/browser/state_names.h" +#include "components/autofill/core/common/autofill_l10n_util.h" #include "components/autofill/core/common/autofill_switches.h" #include "grit/components_strings.h" #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h" @@ -380,27 +381,12 @@ return base::UintToString(hash32); } -scoped_ptr<icu::Collator> CreateCaseInsensitiveCollator() { - UErrorCode error = U_ZERO_ERROR; - scoped_ptr<icu::Collator> collator(icu::Collator::createInstance(error)); - DCHECK(U_SUCCESS(error)); - collator->setStrength(icu::Collator::PRIMARY); - return collator; -} - base::string16 RemoveWhitespace(const base::string16& value) { base::string16 stripped_value; base::RemoveChars(value, base::kWhitespaceUTF16, &stripped_value); return stripped_value; } -bool StringsEqualWithCollator(const base::string16& lhs, - const base::string16& rhs, - const icu::Collator& collator) { - return base::i18n::CompareString16WithCollator(collator, lhs, rhs) == - UCOL_EQUAL; -} - } // namespace AutofillField::AutofillField() @@ -548,21 +534,20 @@ bool AutofillField::FindValueInSelectControl(const FormFieldData& field, const base::string16& value, size_t* index) { - scoped_ptr<icu::Collator> collator = CreateCaseInsensitiveCollator(); - + l10n::CaseInsensitiveCompare compare; // Strip off spaces for all values in the comparisons. const base::string16 value_stripped = RemoveWhitespace(value); for (size_t i = 0; i < field.option_values.size(); ++i) { base::string16 option_value = RemoveWhitespace(field.option_values[i]); - if (StringsEqualWithCollator(value_stripped, option_value, *collator)) { + if (compare.StringsEqual(value_stripped, option_value)) { if (index) *index = i; return true; } base::string16 option_contents = RemoveWhitespace(field.option_contents[i]); - if (StringsEqualWithCollator(value_stripped, option_contents, *collator)) { + if (compare.StringsEqual(value_stripped, option_contents)) { if (index) *index = i; return true;
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc index b8ca3b1..8d26935 100644 --- a/components/autofill/core/browser/autofill_manager.cc +++ b/components/autofill/core/browser/autofill_manager.cc
@@ -705,27 +705,34 @@ client_->HideAutofillPopup(); } -void AutofillManager::RemoveAutofillProfileOrCreditCard(int unique_id) { +bool AutofillManager::RemoveAutofillProfileOrCreditCard(int unique_id) { std::string guid; size_t variant = 0; const CreditCard* credit_card = nullptr; const AutofillProfile* profile = nullptr; if (GetCreditCard(unique_id, &credit_card)) { + if (credit_card->record_type() != CreditCard::LOCAL_CARD) + return false; + guid = credit_card->guid(); } else if (GetProfile(unique_id, &profile, &variant)) { + if (profile->record_type() != AutofillProfile::LOCAL_PROFILE) + return false; + guid = profile->guid(); } else { NOTREACHED(); - return; + return false; } // TODO(csharp): If we are dealing with a variant only the variant should // be deleted, instead of doing nothing. // http://crbug.com/124211 if (variant != 0) - return; + return false; personal_data_->RemoveByGUID(guid); + return true; } void AutofillManager::RemoveAutocompleteEntry(const base::string16& name,
diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h index 7b4b9c4..542e8b8e 100644 --- a/components/autofill/core/browser/autofill_manager.h +++ b/components/autofill/core/browser/autofill_manager.h
@@ -124,8 +124,8 @@ void OnDidPreviewAutofillFormData(); // Remove the credit card or Autofill profile that matches |unique_id| - // from the database. - void RemoveAutofillProfileOrCreditCard(int unique_id); + // from the database. Returns true if deletion is allowed. + bool RemoveAutofillProfileOrCreditCard(int unique_id); // Remove the specified Autocomplete entry. void RemoveAutocompleteEntry(const base::string16& name,
diff --git a/components/autofill/core/browser/autofill_popup_delegate.h b/components/autofill/core/browser/autofill_popup_delegate.h index 97d60976..2eff7c11 100644 --- a/components/autofill/core/browser/autofill_popup_delegate.h +++ b/components/autofill/core/browser/autofill_popup_delegate.h
@@ -28,8 +28,9 @@ virtual void DidAcceptSuggestion(const base::string16& value, int identifier) = 0; - // Delete the described suggestion. - virtual void RemoveSuggestion(const base::string16& value, + // Delete the described suggestion. Returns true if something was deleted, + // or false if deletion is not allowed. + virtual bool RemoveSuggestion(const base::string16& value, int identifier) = 0; // Informs the delegate that the Autofill previewed form should be cleared.
diff --git a/components/autofill/core/browser/autofill_profile.cc b/components/autofill/core/browser/autofill_profile.cc index 9ea27e62..5d582b3 100644 --- a/components/autofill/core/browser/autofill_profile.cc +++ b/components/autofill/core/browser/autofill_profile.cc
@@ -28,6 +28,7 @@ #include "components/autofill/core/browser/phone_number.h" #include "components/autofill/core/browser/phone_number_i18n.h" #include "components/autofill/core/browser/validation.h" +#include "components/autofill/core/common/autofill_l10n_util.h" #include "components/autofill/core/common/form_field_data.h" #include "grit/components_strings.h" #include "third_party/icu/source/common/unicode/uchar.h" @@ -237,21 +238,6 @@ std::string app_locale_; }; -// Functor used to check for case-insensitive equality of two strings. -struct CaseInsensitiveStringEquals { - public: - CaseInsensitiveStringEquals(const base::string16& other) - : other_(other) {} - - bool operator()(const base::string16& x) const { - return x.size() == other_.size() && - base::StringToLowerASCII(x) == base::StringToLowerASCII(other_); - } - - private: - const base::string16& other_; -}; - } // namespace AutofillProfile::AutofillProfile(const std::string& guid, @@ -577,6 +563,8 @@ const AutofillProfile& profile, const std::string& app_locale, const ServerFieldTypeSet& types) const { + scoped_ptr<l10n::CaseInsensitiveCompare> compare; + for (ServerFieldType type : types) { base::string16 value = GetRawInfo(type); if (value.empty()) @@ -599,9 +587,11 @@ app_locale)) { return false; } - } else if (base::StringToLowerASCII(value) != - base::StringToLowerASCII(profile.GetRawInfo(type))) { - return false; + } else { + if (!compare) + compare.reset(new l10n::CaseInsensitiveCompare()); + if (!compare->StringsEqual(value, profile.GetRawInfo(type))) + return false; } } @@ -631,6 +621,7 @@ const std::vector<NameInfo>& names, const std::string& app_locale) { std::vector<NameInfo> results(name_); + l10n::CaseInsensitiveCompare compare; for (std::vector<NameInfo>::const_iterator it = names.begin(); it != names.end(); ++it) { @@ -651,8 +642,8 @@ AutofillType type = AutofillType(NAME_FULL); base::string16 full_name = current_name.GetInfo(type, app_locale); - if (base::StringToLowerASCII(full_name) == - base::StringToLowerASCII(imported_name.GetInfo(type, app_locale))) { + if (compare.StringsEqual(full_name, + imported_name.GetInfo(type, app_locale))) { // The imported name has the same full name string as one of the // existing names for this profile. Because full names are // _heuristically_ parsed into {first, middle, last} name components, @@ -707,6 +698,8 @@ // than full addresses. field_types.erase(ADDRESS_HOME_STREET_ADDRESS); + l10n::CaseInsensitiveCompare compare; + for (ServerFieldTypeSet::const_iterator iter = field_types.begin(); iter != field_types.end(); ++iter) { FieldTypeGroup group = AutofillType(*iter).group(); @@ -719,10 +712,8 @@ // Single value field --- overwrite. if (!AutofillProfile::SupportsMultiValue(*iter)) { base::string16 new_value = profile.GetRawInfo(*iter); - if (base::StringToLowerASCII(GetRawInfo(*iter)) != - base::StringToLowerASCII(new_value)) { + if (!compare.StringsEqual(GetRawInfo(*iter), new_value)) SetRawInfo(*iter, new_value); - } continue; } @@ -754,7 +745,9 @@ } else { existing_iter = std::find_if(existing_values.begin(), existing_values.end(), - CaseInsensitiveStringEquals(*value_iter)); + [&compare, value_iter](base::string16& rhs) { + return compare.StringsEqual(*value_iter, rhs); + }); } if (existing_iter == existing_values.end())
diff --git a/components/autofill/core/browser/autofill_profile_unittest.cc b/components/autofill/core/browser/autofill_profile_unittest.cc index 0303af1..cb5b647f 100644 --- a/components/autofill/core/browser/autofill_profile_unittest.cc +++ b/components/autofill/core/browser/autofill_profile_unittest.cc
@@ -74,9 +74,9 @@ std::vector<base::string16>* middle_names, std::vector<base::string16>* last_names) { for (size_t i = 0; i < names.size(); ++i) { - first_names->push_back(ASCIIToUTF16(names[i].first)); - middle_names->push_back(ASCIIToUTF16(names[i].middle)); - last_names->push_back(ASCIIToUTF16(names[i].last)); + first_names->push_back(UTF8ToUTF16(names[i].first)); + middle_names->push_back(UTF8ToUTF16(names[i].middle)); + last_names->push_back(UTF8ToUTF16(names[i].last)); } } @@ -1301,6 +1301,10 @@ test_cases.push_back(TestCase(NameParts("Marion", "Mitchell", "Morrison"), NameParts("MARION", "MITCHELL", "MORRISON"), NameParts("Marion", "Mitchell", "Morrison"))); + // Capital A with acute versus lower case a with acute. + test_cases.push_back(TestCase(NameParts("M\xc3\xa1rion", "M", "Morrison"), + NameParts("M\xc3\x81rion", "M", "Morrison"), + NameParts("M\xc3\x81rion", "M", "Morrison"))); // A parse that has a two-word last name should take precedence over a // parse that assumes the two names are a middle and a last name.
diff --git a/components/autofill/core/browser/credit_card.cc b/components/autofill/core/browser/credit_card.cc index 85bad41..346d22b5 100644 --- a/components/autofill/core/browser/credit_card.cc +++ b/components/autofill/core/browser/credit_card.cc
@@ -23,6 +23,7 @@ #include "components/autofill/core/browser/autofill_regexes.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/validation.h" +#include "components/autofill/core/common/autofill_l10n_util.h" #include "components/autofill/core/common/form_field_data.h" #include "grit/components_scaled_resources.h" #include "grit/components_strings.h" @@ -70,8 +71,7 @@ // Otherwise, try parsing the |month| as a named month, e.g. "January" or // "Jan". - base::string16 lowercased_month = base::StringToLowerASCII(month); - + l10n::CaseInsensitiveCompare compare; UErrorCode status = U_ZERO_ERROR; icu::Locale locale(app_locale.c_str()); icu::DateFormatSymbols date_format_symbols(locale, status); @@ -81,9 +81,8 @@ int32_t num_months; const icu::UnicodeString* months = date_format_symbols.getMonths(num_months); for (int32_t i = 0; i < num_months; ++i) { - const base::string16 icu_month = base::string16(months[i].getBuffer(), - months[i].length()); - if (lowercased_month == base::StringToLowerASCII(icu_month)) { + const base::string16 icu_month(months[i].getBuffer(), months[i].length()); + if (compare.StringsEqual(icu_month, month)) { *num = i + 1; // Adjust from 0-indexed to 1-indexed. return true; } @@ -91,9 +90,8 @@ months = date_format_symbols.getShortMonths(num_months); for (int32_t i = 0; i < num_months; ++i) { - const base::string16 icu_month = base::string16(months[i].getBuffer(), - months[i].length()); - if (lowercased_month == base::StringToLowerASCII(icu_month)) { + const base::string16 icu_month(months[i].getBuffer(), months[i].length()); + if (compare.StringsEqual(icu_month, month)) { *num = i + 1; // Adjust from 0-indexed to 1-indexed. return true; }
diff --git a/components/autofill/core/browser/credit_card_unittest.cc b/components/autofill/core/browser/credit_card_unittest.cc index dde2b14..2bbadf4 100644 --- a/components/autofill/core/browser/credit_card_unittest.cc +++ b/components/autofill/core/browser/credit_card_unittest.cc
@@ -446,6 +446,12 @@ AutofillType(CREDIT_CARD_EXP_MONTH), ASCIIToUTF16("Apr"), "en-US"); EXPECT_EQ(ASCIIToUTF16("04"), card.GetRawInfo(CREDIT_CARD_EXP_MONTH)); EXPECT_EQ(4, card.expiration_month()); + + card.SetInfo( + AutofillType(CREDIT_CARD_EXP_MONTH), UTF8ToUTF16("F\xc3\x89VRIER"), + "fr-FR"); + EXPECT_EQ(ASCIIToUTF16("02"), card.GetRawInfo(CREDIT_CARD_EXP_MONTH)); + EXPECT_EQ(2, card.expiration_month()); } TEST(CreditCardTest, CreditCardType) {
diff --git a/components/autofill/core/common/BUILD.gn b/components/autofill/core/common/BUILD.gn index e2f7e68..9ba33f3 100644 --- a/components/autofill/core/common/BUILD.gn +++ b/components/autofill/core/common/BUILD.gn
@@ -8,6 +8,8 @@ "autofill_constants.h", "autofill_data_validation.cc", "autofill_data_validation.h", + "autofill_l10n_util.cc", + "autofill_l10n_util.h", "autofill_pref_names.cc", "autofill_pref_names.h", "autofill_switches.cc",
diff --git a/components/autofill/core/common/autofill_l10n_util.cc b/components/autofill/core/common/autofill_l10n_util.cc new file mode 100644 index 0000000..6f063a85 --- /dev/null +++ b/components/autofill/core/common/autofill_l10n_util.cc
@@ -0,0 +1,30 @@ +// 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/autofill/core/common/autofill_l10n_util.h" + +#include "base/i18n/string_compare.h" +#include "base/logging.h" + +namespace autofill { +namespace l10n { + +CaseInsensitiveCompare::CaseInsensitiveCompare() { + UErrorCode error = U_ZERO_ERROR; + collator_.reset(icu::Collator::createInstance(error)); + DCHECK(U_SUCCESS(error)); + collator_->setStrength(icu::Collator::PRIMARY); +} + +CaseInsensitiveCompare::~CaseInsensitiveCompare() { +} + +bool CaseInsensitiveCompare::StringsEqual(const base::string16& lhs, + const base::string16& rhs) const { + return base::i18n::CompareString16WithCollator(*collator_, lhs, rhs) == + UCOL_EQUAL; +} + +} // namespace l10n +} // namespace autofill
diff --git a/components/autofill/core/common/autofill_l10n_util.h b/components/autofill/core/common/autofill_l10n_util.h new file mode 100644 index 0000000..099eb3af --- /dev/null +++ b/components/autofill/core/common/autofill_l10n_util.h
@@ -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 "base/memory/scoped_ptr.h" +#include "base/strings/string16.h" +#include "third_party/icu/source/i18n/unicode/coll.h" + +namespace autofill { +namespace l10n { + +// Assists with locale-aware case insensitive string comparisons. +class CaseInsensitiveCompare { + public: + CaseInsensitiveCompare(); + ~CaseInsensitiveCompare(); + + bool StringsEqual(const base::string16& lhs, const base::string16& rhs) const; + + private: + scoped_ptr<icu::Collator> collator_; + + DISALLOW_COPY_AND_ASSIGN(CaseInsensitiveCompare); +}; + +} // namespace l10n +} // namespace autofill
diff --git a/components/components_browsertests.isolate b/components/components_browsertests.isolate index f384f85f..2dff53ae 100644 --- a/components/components_browsertests.isolate +++ b/components/components_browsertests.isolate
@@ -39,6 +39,7 @@ 'files': [ 'test/data/', '../testing/test_env.py', + '../third_party/dom_distiller_js/dist/test/data/', '<(PRODUCT_DIR)/components_browsertests<(EXECUTABLE_SUFFIX)', '<(PRODUCT_DIR)/components_tests_resources.pak', '<(PRODUCT_DIR)/content_shell.pak',
diff --git a/components/components_tests.gyp b/components/components_tests.gyp index a1ab4f8..55029d9 100644 --- a/components/components_tests.gyp +++ b/components/components_tests.gyp
@@ -403,6 +403,7 @@ 'proximity_auth/cryptauth/cryptauth_access_token_fetcher_impl_unittest.cc', 'proximity_auth/cryptauth/cryptauth_api_call_flow_unittest.cc', 'proximity_auth/cryptauth/cryptauth_client_impl_unittest.cc', + 'proximity_auth/cryptauth/cryptauth_enroller_impl_unittest.cc', 'proximity_auth/cryptauth/fake_secure_message_delegate_unittest.cc', 'proximity_auth/proximity_auth_system_unittest.cc', 'proximity_auth/remote_status_update_unittest.cc', @@ -1122,6 +1123,7 @@ 'autofill/content/renderer/password_form_conversion_utils_browsertest.cc', 'dom_distiller/content/distillable_page_utils_browsertest.cc', 'dom_distiller/content/distiller_page_web_contents_browsertest.cc', + 'dom_distiller/content/test/dom_distiller_js_browsertest.cc', 'password_manager/content/renderer/credential_manager_client_browsertest.cc', ], 'conditions': [
diff --git a/components/content_settings/core/browser/content_settings_default_provider.cc b/components/content_settings/core/browser/content_settings_default_provider.cc index 4d3e08b6..0af5197 100644 --- a/components/content_settings/core/browser/content_settings_default_provider.cc +++ b/components/content_settings/core/browser/content_settings_default_provider.cc
@@ -249,9 +249,14 @@ scoped_ptr<base::Value> value(in_value); { base::AutoReset<bool> auto_reset(&updating_preferences_, true); - base::AutoLock lock(lock_); - - ChangeSetting(content_type, value.get()); + // Lock the memory map access, so that values are not read by + // |GetRuleIterator| at the same time as they are written here. Do not lock + // the preference access though; preference updates send out notifications + // whose callbacks may try to reacquire the lock on the same thread. + { + base::AutoLock lock(lock_); + ChangeSetting(content_type, value.get()); + } WriteIndividualPref(content_type, value.get()); // If the changed setting is syncable, write it to the old dictionary @@ -374,19 +379,31 @@ // If the dictionary preference gets synced from an old version // of Chrome, we should update all individual preferences that // are marked as syncable. - base::AutoLock lock(lock_); base::AutoReset<bool> auto_reset(&updating_preferences_, true); scoped_ptr<ValueMap> dictionary = ReadDictionaryPref(); + // Lock the memory map access, so that values are not read by + // |GetRuleIterator| at the same time as they are written here. Do not lock + // the preference access though; preference updates send out notifications + // whose callbacks may try to reacquire the lock on the same thread. + { + base::AutoLock lock(lock_); + for (const auto& it : *dictionary) { + if (!IsContentSettingsTypeSyncable(it.first)) + continue; + + DCHECK(default_settings_.find(it.first) != default_settings_.end()); + ChangeSetting(it.first, it.second.get()); + to_notify.push_back(it.first); + } + } + + // When the lock is released, write the new settings to preferences. for (const auto& it : *dictionary) { if (!IsContentSettingsTypeSyncable(it.first)) continue; - - DCHECK(default_settings_.find(it.first) != default_settings_.end()); - ChangeSetting(it.first, it.second.get()); WriteIndividualPref(it.first, it.second.get()); - to_notify.push_back(it.first); } } else { // Find out which content setting the preference corresponds to. @@ -407,10 +424,16 @@ // A new individual preference is changed. If it is syncable, we should // change its entry in the dictionary preference as well, so that it // can be synced to older versions of Chrome. - base::AutoLock lock(lock_); base::AutoReset<bool> auto_reset(&updating_preferences_, true); - ChangeSetting(content_type, ReadIndividualPref(content_type).get()); + // Lock the memory map access, so that values are not read by + // |GetRuleIterator| at the same time as they are written here. Do not lock + // the preference access though; preference updates send out notifications + // whose callbacks may try to reacquire the lock on the same thread. + { + base::AutoLock lock(lock_); + ChangeSetting(content_type, ReadIndividualPref(content_type).get()); + } if (IsContentSettingsTypeSyncable(content_type)) WriteDictionaryPref(content_type, default_settings_[content_type].get()); to_notify.push_back(content_type);
diff --git a/components/content_settings/core/browser/content_settings_pref.cc b/components/content_settings/core/browser/content_settings_pref.cc index 4c48da3..10357322 100644 --- a/components/content_settings/core/browser/content_settings_pref.cc +++ b/components/content_settings/core/browser/content_settings_pref.cc
@@ -161,33 +161,24 @@ if (!is_incognito_) map_to_modify = &value_map_; - std::vector<Rule> rules_to_delete; { base::AutoLock auto_lock(lock_); - scoped_ptr<RuleIterator> rule_iterator( - map_to_modify->GetRuleIterator(content_type_, - ResourceIdentifier(), - NULL)); - // Copy the rules; we cannot call |UpdatePref| while holding |lock_|. - while (rule_iterator->HasNext()) - rules_to_delete.push_back(rule_iterator->Next()); - - map_to_modify->DeleteValues(content_type_, ResourceIdentifier()); + map_to_modify->clear(); } - for (std::vector<Rule>::const_iterator it = rules_to_delete.begin(); - it != rules_to_delete.end(); ++it) { - UpdatePref(it->primary_pattern, - it->secondary_pattern, - ResourceIdentifier(), - NULL); - if (IsContentSettingsTypeSyncable(content_type_)) { - UpdateOldPref(it->primary_pattern, - it->secondary_pattern, - ResourceIdentifier(), - NULL); + if (!is_incognito_) { + // Clear the new preference. + { + base::AutoReset<bool> auto_reset(&updating_preferences_, true); + DictionaryPrefUpdate update(prefs_, pref_name_); + base::DictionaryValue* pattern_pairs_settings = update.Get(); + pattern_pairs_settings->Clear(); } + + if (IsContentSettingsTypeSyncable(content_type_)) + ClearOldPreference(); } + notify_callback_.Run(ContentSettingsPattern(), ContentSettingsPattern(), content_type_,
diff --git a/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequestFactory.java b/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequestFactory.java index 6c54949..75846c4 100644 --- a/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequestFactory.java +++ b/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequestFactory.java
@@ -7,7 +7,7 @@ import android.content.Context; import android.os.Build; -import org.chromium.base.UsedByReflection; +import org.chromium.base.annotations.UsedByReflection; import java.nio.channels.WritableByteChannel; import java.util.Map;
diff --git a/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java b/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java index a2d6446..78d3bee0 100644 --- a/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java +++ b/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java
@@ -15,7 +15,7 @@ import org.chromium.base.CalledByNative; import org.chromium.base.JNINamespace; import org.chromium.base.NativeClassQualifiedName; -import org.chromium.base.UsedByReflection; +import org.chromium.base.annotations.UsedByReflection; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger;
diff --git a/components/cronet/android/proguard.cfg b/components/cronet/android/proguard.cfg index 3930cb94..65f4333 100644 --- a/components/cronet/android/proguard.cfg +++ b/components/cronet/android/proguard.cfg
@@ -2,7 +2,7 @@ -keep class org.chromium.base.*Native* -keep class org.chromium.base.JNINamespace -keepclasseswithmembers class org.chromium.** { - @org.chromium.base.AccessedByNative <fields>; + @org.chromium.base.annotations.AccessedByNative <fields>; } -keepclasseswithmembers class org.chromium.** { @org.chromium.base.*Native* <methods>;
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java index 7022057..85400f36 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java
@@ -32,7 +32,7 @@ @SmallTest @Feature({"Cronet"}) - public void disabled_testQuicLoadUrl() throws Exception { + public void testQuicLoadUrl() throws Exception { HttpUrlRequestFactoryConfig config = new HttpUrlRequestFactoryConfig(); String quicURL = QuicTestServer.getServerURL() + "/simple.txt"; config.enableQUIC(true); @@ -47,9 +47,8 @@ HashMap<String, String> headers = new HashMap<String, String>(); TestHttpUrlRequestListener listener = new TestHttpUrlRequestListener(); - // Quic always races the first request with SPDY. Since our test server - // only supports Quic, request will either succeed with a 200 or fail - // with a 500. + // Quic always races the first request with SPDY, but the second request + // should go through Quic. for (int i = 0; i < 2; i++) { HttpUrlRequest request = factory.createRequest( @@ -59,8 +58,6 @@ listener); request.start(); listener.blockForComplete(); - assertTrue(listener.mHttpStatusCode == 200 - || listener.mHttpStatusCode == 500); if (listener.mHttpStatusCode == 200) break; } assertEquals(200, listener.mHttpStatusCode);
diff --git a/components/cronet/android/test/quic_test_server.cc b/components/cronet/android/test/quic_test_server.cc index 04dfd549..ff0b859e 100644 --- a/components/cronet/android/test/quic_test_server.cc +++ b/components/cronet/android/test/quic_test_server.cc
@@ -25,19 +25,23 @@ base::Thread* g_quic_server_thread = nullptr; net::tools::QuicSimpleServer* g_quic_server = nullptr; -void ServeFilesFromDirectory(const base::FilePath& directory) { +void ServeFilesFromDirectory( + const base::FilePath& directory, + base::android::ScopedJavaGlobalRef<jobject>* callback) { DCHECK(g_quic_server_thread->task_runner()->BelongsToCurrentThread()); DCHECK(!g_quic_server); base::FilePath file_dir = directory.Append("quic_data"); net::tools::QuicInMemoryCache::GetInstance()->InitializeFromDirectory( file_dir.value()); net::IPAddressNumber ip; - DCHECK(net::ParseIPLiteralToNumber(kServerHost, &ip)); + net::ParseIPLiteralToNumber(kServerHost, &ip); net::QuicConfig config; g_quic_server = new net::tools::QuicSimpleServer(config, net::QuicSupportedVersions()); - DCHECK(g_quic_server->Listen(net::IPEndPoint(ip, kServerPort)) >= 0) << - "Quic server fails to start"; + int rv = g_quic_server->Listen(net::IPEndPoint(ip, kServerPort)); + CHECK_GE(rv, 0) << "Quic server fails to start"; + JNIEnv* env = base::android::AttachCurrentThread(); + Java_QuicTestServer_onServerStarted(env, callback->obj()); } void ShutdownOnServerThread() { @@ -57,11 +61,16 @@ g_quic_server_thread = new base::Thread("quic server thread"); base::Thread::Options thread_options; thread_options.message_loop_type = base::MessageLoop::TYPE_IO; - DCHECK(g_quic_server_thread->StartWithOptions(thread_options)); + bool started = g_quic_server_thread->StartWithOptions(thread_options); + DCHECK(started); base::FilePath test_files_root( base::android::ConvertJavaStringToUTF8(env, jtest_files_root)); + base::android::ScopedJavaGlobalRef<jobject>* callback = + new base::android::ScopedJavaGlobalRef<jobject>(); + callback->Reset(env, jcaller); g_quic_server_thread->task_runner()->PostTask( - FROM_HERE, base::Bind(&ServeFilesFromDirectory, test_files_root)); + FROM_HERE, base::Bind(&ServeFilesFromDirectory, test_files_root, + base::Owned(callback))); } void ShutdownQuicTestServer(JNIEnv* env, jclass jcaller) {
diff --git a/components/cronet/android/test/src/org/chromium/net/QuicTestServer.java b/components/cronet/android/test/src/org/chromium/net/QuicTestServer.java index b299156..78fbfde7 100644 --- a/components/cronet/android/test/src/org/chromium/net/QuicTestServer.java +++ b/components/cronet/android/test/src/org/chromium/net/QuicTestServer.java
@@ -5,7 +5,9 @@ package org.chromium.net; import android.content.Context; +import android.os.ConditionVariable; +import org.chromium.base.CalledByNative; import org.chromium.base.JNINamespace; /** @@ -13,12 +15,16 @@ */ @JNINamespace("cronet") public final class QuicTestServer { + private static final ConditionVariable sBlock = new ConditionVariable(); + public static void startQuicTestServer(Context context) { nativeStartQuicTestServer(TestFilesInstaller.getInstalledPath(context)); + sBlock.block(); } public static void shutdownQuicTestServer() { nativeShutdownQuicTestServer(); + sBlock.close(); } public static String getServerURL() { @@ -33,6 +39,11 @@ return nativeGetServerPort(); } + @CalledByNative + private void onServerStarted() { + sBlock.open(); + } + private static native void nativeStartQuicTestServer(String filePath); private static native void nativeShutdownQuicTestServer(); private static native String nativeGetServerHost();
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 59081c3..f8e3d9e 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
@@ -12,7 +12,6 @@ #include "base/json/json_writer.h" #include "base/location.h" #include "base/logging.h" -#include "base/single_thread_task_runner.h" #include "base/time/time.h" #include "base/values.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h" @@ -86,22 +85,17 @@ const net::BackoffEntry::Policy& backoff_policy, DataReductionProxyRequestOptions* request_options, DataReductionProxyMutableConfigValues* config_values, - DataReductionProxyConfig* config, - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) + DataReductionProxyConfig* config) : params_(params.Pass()), request_options_(request_options), config_values_(config_values), config_(config), - io_task_runner_(io_task_runner), backoff_entry_(&backoff_policy) { DCHECK(request_options); DCHECK(config_values); DCHECK(config); - DCHECK(io_task_runner.get()); - io_task_runner_->PostTask( - FROM_HERE, - base::Bind(&DataReductionProxyConfigServiceClient::RetrieveConfig, - base::Unretained(this))); + // Constructed on the UI thread, but should be checked on the IO thread. + thread_checker_.DetachFromThread(); } DataReductionProxyConfigServiceClient:: @@ -109,8 +103,7 @@ } void DataReductionProxyConfigServiceClient::RetrieveConfig() { - DCHECK(io_task_runner_->BelongsToCurrentThread()); - + DCHECK(thread_checker_.CalledOnValidThread()); std::string static_response = ConstructStaticResponse(); ClientConfig config; bool succeeded = false;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h index 3f6ae23..e51ea83 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h
@@ -9,13 +9,12 @@ #include "base/gtest_prod_util.h" #include "base/macros.h" -#include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "base/threading/thread_checker.h" #include "base/timer/timer.h" #include "net/base/backoff_entry.h" namespace base { -class SingleThreadTaskRunner; class Time; class TimeDelta; } @@ -43,8 +42,7 @@ const net::BackoffEntry::Policy& backoff_policy, DataReductionProxyRequestOptions* request_options, DataReductionProxyMutableConfigValues* config_values, - DataReductionProxyConfig* config, - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner); + DataReductionProxyConfig* config); virtual ~DataReductionProxyConfigServiceClient(); @@ -86,10 +84,6 @@ // The caller must ensure that the |config_| outlives this instance. DataReductionProxyConfig* config_; - // |io_task_runner_| should be the task runner for running operations on the - // IO thread. - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; - // Used to calculate the backoff time on request failures. net::BackoffEntry backoff_entry_; @@ -98,6 +92,9 @@ base::OneShotTimer<DataReductionProxyConfigServiceClient> config_refresh_timer_; + // Enforce usage on the IO thread. + base::ThreadChecker thread_checker_; + DISALLOW_COPY_AND_ASSIGN(DataReductionProxyConfigServiceClient); };
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc index f8e7c0f3..b72ee5746 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
@@ -75,16 +75,13 @@ DataReductionProxyParams::kAllowed | DataReductionProxyParams::kFallbackAllowed | DataReductionProxyParams::kPromoAllowed)); - request_options_.reset( - new DataReductionProxyRequestOptions(Client::UNKNOWN, - test_context_->io_data()->config(), - test_context_->task_runner())); + request_options_.reset(new DataReductionProxyRequestOptions( + Client::UNKNOWN, test_context_->io_data()->config())); return scoped_ptr<DataReductionProxyConfigServiceClient>( new DataReductionProxyConfigServiceClient( - params.Pass(), GetBackoffPolicy(), - request_options_.get(), + params.Pass(), GetBackoffPolicy(), request_options_.get(), test_context_->mutable_config_values(), - test_context_->io_data()->config(), test_context_->task_runner())); + test_context_->io_data()->config())); } DataReductionProxyParams* params() { @@ -133,7 +130,7 @@ .WillRepeatedly( testing::Invoke(&populator, &RequestOptionsPopulator::PopulateResponse)); - RunUntilIdle(); + config_client()->RetrieveConfig(); EXPECT_EQ(base::TimeDelta::FromDays(1), config_client()->GetDelay()); EXPECT_EQ(params()->origin().ToURI(), configurator()->origin()); EXPECT_EQ(params()->fallback_origin().ToURI(), @@ -162,7 +159,7 @@ .Times(1) .WillOnce(testing::Invoke(&populator, &RequestOptionsPopulator::PopulateResponse)); - RunUntilIdle(); + config_client()->RetrieveConfig(); EXPECT_EQ(base::TimeDelta::FromSeconds(10), config_client()->GetDelay()); EXPECT_EQ(params()->origin().ToURI(), configurator()->origin()); EXPECT_EQ(params()->fallback_origin().ToURI(), @@ -202,7 +199,7 @@ .Times(1) .WillOnce(testing::Invoke(&populator, &RequestOptionsPopulator::PopulateResponse)); - RunUntilIdle(); + config_client()->RetrieveConfig(); EXPECT_TRUE(configurator()->origin().empty()); EXPECT_TRUE(configurator()->fallback_origin().empty()); EXPECT_TRUE(configurator()->ssl_origin().empty());
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.cc index 4009c21..2a804f1 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.cc
@@ -4,7 +4,6 @@ #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h" -#include "base/sequenced_task_runner.h" #include "base/strings/string_util.h" #include "base/values.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.h" @@ -13,15 +12,13 @@ namespace data_reduction_proxy { DataReductionProxyConfigurator::DataReductionProxyConfigurator( - scoped_refptr<base::SequencedTaskRunner> network_task_runner, net::NetLog* net_log, DataReductionProxyEventStore* event_store) - : network_task_runner_(network_task_runner), - net_log_(net_log), - data_reduction_proxy_event_store_(event_store) { - DCHECK(network_task_runner.get()); + : net_log_(net_log), data_reduction_proxy_event_store_(event_store) { DCHECK(net_log); DCHECK(event_store); + // Constructed on the UI thread, but should be checked on the IO thread. + thread_checker_.DetachFromThread(); } DataReductionProxyConfigurator::~DataReductionProxyConfigurator() { @@ -33,6 +30,7 @@ const std::string& primary_origin, const std::string& fallback_origin, const std::string& ssl_origin) { + DCHECK(thread_checker_.CalledOnValidThread()); std::vector<std::string> proxies; if (!primary_restricted) { std::string trimmed_primary; @@ -68,32 +66,25 @@ data_reduction_proxy_event_store_->AddProxyEnabledEvent( net_log_, primary_restricted, fallback_restricted, primary_origin, fallback_origin, ssl_origin); - network_task_runner_->PostTask( - FROM_HERE, - base::Bind( - &DataReductionProxyConfigurator::UpdateProxyConfigOnIOThread, - base::Unretained(this), - config)); + config_ = config; } void DataReductionProxyConfigurator::Disable() { + DCHECK(thread_checker_.CalledOnValidThread()); net::ProxyConfig config = net::ProxyConfig::CreateDirect(); data_reduction_proxy_event_store_->AddProxyDisabledEvent(net_log_); - network_task_runner_->PostTask( - FROM_HERE, - base::Bind( - &DataReductionProxyConfigurator::UpdateProxyConfigOnIOThread, - base::Unretained(this), - config)); + config_ = config; } void DataReductionProxyConfigurator::AddHostPatternToBypass( const std::string& pattern) { + DCHECK(thread_checker_.CalledOnValidThread()); bypass_rules_.push_back(pattern); } void DataReductionProxyConfigurator::AddURLPatternToBypass( const std::string& pattern) { + DCHECK(thread_checker_.CalledOnValidThread()); size_t pos = pattern.find('/'); if (pattern.find('/', pos + 1) == pos + 1) pos = pattern.find('/', pos + 2); @@ -107,13 +98,8 @@ AddHostPatternToBypass(host_pattern); } -void DataReductionProxyConfigurator::UpdateProxyConfigOnIOThread( - const net::ProxyConfig& config) { - config_ = config; -} - -const net::ProxyConfig& -DataReductionProxyConfigurator::GetProxyConfigOnIOThread() const { +const net::ProxyConfig& DataReductionProxyConfigurator::GetProxyConfig() const { + DCHECK(thread_checker_.CalledOnValidThread()); return config_; }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h index 82b1d09..e239b542 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h
@@ -9,13 +9,9 @@ #include <vector> #include "base/gtest_prod_util.h" -#include "base/task_runner.h" +#include "base/threading/thread_checker.h" #include "net/proxy/proxy_config.h" -namespace base { -class SequencedTaskRunner; -} - namespace net { class NetLog; class ProxyInfo; @@ -30,23 +26,15 @@ class DataReductionProxyConfigurator { public: - // Constructs a configurator. |network_task_runner| should be the task runner - // for running network operations, |net_log| and |event_store| are used to + // Constructs a configurator. |net_log| and |event_store| are used to // track network and Data Reduction Proxy events respectively, must not be // null, and must outlive this instance. DataReductionProxyConfigurator( - scoped_refptr<base::SequencedTaskRunner> network_task_runner, net::NetLog* net_log, DataReductionProxyEventStore* event_store); virtual ~DataReductionProxyConfigurator(); - void set_net_log(net::NetLog* net_log) { - DCHECK(!net_log_); - net_log_ = net_log; - DCHECK(net_log_); - } - // Constructs a proxy configuration suitable for enabling the Data Reduction // proxy. virtual void Enable(bool primary_restricted, @@ -71,19 +59,13 @@ // as a hostname pattern. virtual void AddURLPatternToBypass(const std::string& pattern); - // Updates the config for use on the IO thread. - void UpdateProxyConfigOnIOThread(const net::ProxyConfig& config); - // Returns the current data reduction proxy config, even if it is not the // effective configuration used by the proxy service. - const net::ProxyConfig& GetProxyConfigOnIOThread() const; + const net::ProxyConfig& GetProxyConfig() const; private: FRIEND_TEST_ALL_PREFIXES(DataReductionProxyConfiguratorTest, TestBypassList); - // Used for updating the proxy config on the IO thread. - scoped_refptr<base::SequencedTaskRunner> network_task_runner_; - // Rules for bypassing the Data Reduction Proxy. std::vector<std::string> bypass_rules_; @@ -96,6 +78,9 @@ net::NetLog* net_log_; DataReductionProxyEventStore* data_reduction_proxy_event_store_; + // Enforce usage on the IO thread. + base::ThreadChecker thread_checker_; + DISALLOW_COPY_AND_ASSIGN(DataReductionProxyConfigurator); };
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_test_utils.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_test_utils.cc index a86845f..e373aad 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_test_utils.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_test_utils.cc
@@ -7,10 +7,9 @@ namespace data_reduction_proxy { TestDataReductionProxyConfigurator::TestDataReductionProxyConfigurator( - scoped_refptr<base::SequencedTaskRunner> network_task_runner, net::NetLog* net_log, DataReductionProxyEventStore* event_store) - : DataReductionProxyConfigurator(network_task_runner, net_log, event_store), + : DataReductionProxyConfigurator(net_log, event_store), enabled_(false), restricted_(false), fallback_restricted_(false) {
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_test_utils.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_test_utils.h index 5b0a82c9..bcfccd5 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_test_utils.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_test_utils.h
@@ -7,8 +7,6 @@ #include <string> -#include "base/memory/ref_counted.h" -#include "base/sequenced_task_runner.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h" namespace net { @@ -23,7 +21,6 @@ : public DataReductionProxyConfigurator { public: TestDataReductionProxyConfigurator( - scoped_refptr<base::SequencedTaskRunner> network_task_runner, net::NetLog* net_log, DataReductionProxyEventStore* event_store); ~TestDataReductionProxyConfigurator() override;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_unittest.cc index b821a25..bb8fb3d 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_unittest.cc
@@ -23,10 +23,8 @@ net_log_.reset(new net::CapturingNetLog()); data_reduction_proxy_event_store_.reset( new data_reduction_proxy::DataReductionProxyEventStore(task_runner_)); - config_.reset( - new DataReductionProxyConfigurator( - task_runner_, net_log_.get(), - data_reduction_proxy_event_store_.get())); + config_.reset(new DataReductionProxyConfigurator( + net_log_.get(), data_reduction_proxy_event_store_.get())); } void CheckProxyConfig( @@ -36,7 +34,7 @@ const std::string& expected_bypass_list) { task_runner_->RunUntilIdle(); const net::ProxyConfig::ProxyRules& rules = - config_->GetProxyConfigOnIOThread().proxy_rules(); + config_->GetProxyConfig().proxy_rules(); ASSERT_EQ(expected_rules_type, rules.type); if (net::ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME == expected_rules_type) {
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc index c257d67..8475211 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc
@@ -302,7 +302,7 @@ // Three proxies should be available for use: primary, fallback, and direct. const net::ProxyConfig& proxy_config = - drp_test_context_->configurator()->GetProxyConfigOnIOThread(); + drp_test_context_->configurator()->GetProxyConfig(); EXPECT_EQ(3U, proxy_config.proxy_rules().proxies_for_http.size()); }
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 8fd3ef51..d025624f 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
@@ -48,14 +48,13 @@ new DataReductionProxyParams(param_flags)); params->EnableQuic(enable_quic); event_store_.reset(new DataReductionProxyEventStore(ui_task_runner)); - configurator_.reset(new DataReductionProxyConfigurator( - io_task_runner, net_log, event_store_.get())); + configurator_.reset( + new DataReductionProxyConfigurator(net_log, event_store_.get())); bool use_config_client = DataReductionProxyParams::IsConfigClientEnabled(); DataReductionProxyMutableConfigValues* raw_mutable_config = nullptr; if (use_config_client) { scoped_ptr<DataReductionProxyMutableConfigValues> mutable_config = - DataReductionProxyMutableConfigValues::CreateFromParams(io_task_runner_, - params.get()); + DataReductionProxyMutableConfigValues::CreateFromParams(params.get()); raw_mutable_config = mutable_config.get(); config_.reset(new DataReductionProxyConfig( io_task_runner_, ui_task_runner_, net_log, mutable_config.Pass(), @@ -72,13 +71,13 @@ bypass_stats_.reset(new DataReductionProxyBypassStats( config_.get(), base::Bind(&DataReductionProxyIOData::SetUnreachable, base::Unretained(this)))); - request_options_.reset(new DataReductionProxyRequestOptions( - client_, config_.get(), io_task_runner_)); + request_options_.reset( + new DataReductionProxyRequestOptions(client_, config_.get())); request_options_->Init(); if (use_config_client) { config_client_.reset(new DataReductionProxyConfigServiceClient( params.Pass(), GetBackoffPolicy(), request_options_.get(), - raw_mutable_config, config_.get(), io_task_runner_)); + raw_mutable_config, config_.get())); } proxy_delegate_.reset( @@ -122,6 +121,8 @@ void DataReductionProxyIOData::InitializeOnIOThread() { DCHECK(io_task_runner_->BelongsToCurrentThread()); + if (config_client_.get()) + config_client_->RetrieveConfig(); ui_task_runner_->PostTask( FROM_HERE, base::Bind(&DataReductionProxyService::SetIOData,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.cc index cebbdaca..19f935e 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.cc
@@ -4,17 +4,15 @@ #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h" -#include "base/single_thread_task_runner.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h" namespace data_reduction_proxy { scoped_ptr<DataReductionProxyMutableConfigValues> DataReductionProxyMutableConfigValues::CreateFromParams( - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, const DataReductionProxyParams* params) { scoped_ptr<DataReductionProxyMutableConfigValues> config_values( - new DataReductionProxyMutableConfigValues(io_task_runner)); + new DataReductionProxyMutableConfigValues()); config_values->promo_allowed_ = params->promo_allowed(); config_values->holdback_ = params->holdback(); config_values->allowed_ = params->allowed(); @@ -23,17 +21,16 @@ return config_values.Pass(); } -DataReductionProxyMutableConfigValues::DataReductionProxyMutableConfigValues( - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) +DataReductionProxyMutableConfigValues::DataReductionProxyMutableConfigValues() : empty_origin_(), promo_allowed_(false), holdback_(false), allowed_(false), fallback_allowed_(false), origin_(empty_origin_), - fallback_origin_(empty_origin_), - io_task_runner_(io_task_runner) { - DCHECK(io_task_runner.get()); + fallback_origin_(empty_origin_) { + // Constructed on the UI thread, but should be checked on the IO thread. + thread_checker_.DetachFromThread(); } DataReductionProxyMutableConfigValues:: @@ -99,13 +96,13 @@ } const net::ProxyServer& DataReductionProxyMutableConfigValues::origin() const { - DCHECK(io_task_runner_->BelongsToCurrentThread()); + DCHECK(thread_checker_.CalledOnValidThread()); return origin_; } const net::ProxyServer& DataReductionProxyMutableConfigValues::fallback_origin() const { - DCHECK(io_task_runner_->BelongsToCurrentThread()); + DCHECK(thread_checker_.CalledOnValidThread()); return fallback_origin_; } @@ -132,7 +129,7 @@ void DataReductionProxyMutableConfigValues::UpdateValues( const net::ProxyServer& origin, const net::ProxyServer& fallback_origin) { - DCHECK(io_task_runner_->BelongsToCurrentThread()); + DCHECK(thread_checker_.CalledOnValidThread()); origin_ = origin; fallback_origin_ = fallback_origin; }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h index 6897cb9..264ef17 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h
@@ -6,16 +6,12 @@ #define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_MUTABLE_CONFIG_VALUES_H_ #include "base/macros.h" -#include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "base/threading/thread_checker.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_config_values.h" #include "net/proxy/proxy_server.h" #include "url/gurl.h" -namespace base { -class SingleThreadTaskRunner; -} - namespace data_reduction_proxy { class DataReductionProxyParams; @@ -28,7 +24,6 @@ // Creates a new |DataReductionProxyMutableConfigValues| using |params| as // the basis for its initial values. static scoped_ptr<DataReductionProxyMutableConfigValues> CreateFromParams( - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, const DataReductionProxyParams* params); ~DataReductionProxyMutableConfigValues() override; @@ -57,8 +52,7 @@ const GURL& secure_proxy_check_url() const override; protected: - DataReductionProxyMutableConfigValues( - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner); + DataReductionProxyMutableConfigValues(); private: net::ProxyServer empty_origin_; @@ -70,9 +64,8 @@ net::ProxyServer fallback_origin_; GURL secure_proxy_check_url_; - // |io_task_runner_| should be the task runner for running operations on the - // IO thread. - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; + // Enforce usage on the IO thread. + base::ThreadChecker thread_checker_; DISALLOW_COPY_AND_ASSIGN(DataReductionProxyMutableConfigValues); };
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 c9b9cb1b..6ef70dc 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
@@ -81,10 +81,11 @@ : LayeredNetworkDelegate(network_delegate.Pass()), received_content_length_(0), original_content_length_(0), - data_reduction_proxy_enabled_(NULL), + data_reduction_proxy_enabled_(nullptr), data_reduction_proxy_config_(config), - data_reduction_proxy_bypass_stats_(NULL), + data_reduction_proxy_bypass_stats_(nullptr), data_reduction_proxy_request_options_(request_options), + data_reduction_proxy_io_data_(nullptr), configurator_(configurator) { DCHECK(data_reduction_proxy_config_); DCHECK(data_reduction_proxy_request_options_); @@ -121,9 +122,9 @@ const net::ProxyService& proxy_service, net::ProxyInfo* result) { if (configurator_) { - OnResolveProxyHandler( - url, load_flags, configurator_->GetProxyConfigOnIOThread(), - proxy_service.proxy_retry_info(), data_reduction_proxy_config_, result); + OnResolveProxyHandler(url, load_flags, configurator_->GetProxyConfig(), + proxy_service.proxy_retry_info(), + data_reduction_proxy_config_, result); } } @@ -175,10 +176,9 @@ request->response_info().headers->GetFreshnessLifetimes( request->response_info().response_time).freshness; DataReductionProxyRequestType request_type = - GetDataReductionProxyRequestType( - *request, - configurator_->GetProxyConfigOnIOThread(), - *data_reduction_proxy_config_); + GetDataReductionProxyRequestType(*request, + configurator_->GetProxyConfig(), + *data_reduction_proxy_config_); int64 adjusted_original_content_length = GetAdjustedOriginalContentLength(request_type, @@ -194,9 +194,8 @@ if (data_reduction_proxy_enabled_ && data_reduction_proxy_bypass_stats_) { data_reduction_proxy_bypass_stats_->RecordBytesHistograms( - *request, - *data_reduction_proxy_enabled_, - configurator_->GetProxyConfigOnIOThread()); + *request, *data_reduction_proxy_enabled_, + configurator_->GetProxyConfig()); } DVLOG(2) << __FUNCTION__ << " received content length: " << received_content_length
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 1b95890b..8bd3d23 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
@@ -96,25 +96,25 @@ DataReductionProxyRequestOptions::DataReductionProxyRequestOptions( Client client, - DataReductionProxyConfig* config, - scoped_refptr<base::SingleThreadTaskRunner> network_task_runner) + DataReductionProxyConfig* config) : client_(GetString(client)), use_assigned_credentials_(false), - data_reduction_proxy_config_(config), - network_task_runner_(network_task_runner) { + data_reduction_proxy_config_(config) { GetChromiumBuildAndPatch(ChromiumVersion(), &build_, &patch_); + // Constructed on the UI thread, but should be checked on the IO thread. + thread_checker_.DetachFromThread(); } DataReductionProxyRequestOptions::DataReductionProxyRequestOptions( Client client, const std::string& version, - DataReductionProxyConfig* config, - scoped_refptr<base::SingleThreadTaskRunner> network_task_runner) + DataReductionProxyConfig* config) : client_(GetString(client)), use_assigned_credentials_(false), - data_reduction_proxy_config_(config), - network_task_runner_(network_task_runner) { + data_reduction_proxy_config_(config) { GetChromiumBuildAndPatch(version, &build_, &patch_); + // Constructed on the UI thread, but should be checked on the IO thread. + thread_checker_.DetachFromThread(); } DataReductionProxyRequestOptions::~DataReductionProxyRequestOptions() { @@ -208,7 +208,7 @@ net::URLRequest* request, const net::ProxyServer& proxy_server, net::HttpRequestHeaders* request_headers) { - DCHECK(network_task_runner_->BelongsToCurrentThread()); + DCHECK(thread_checker_.CalledOnValidThread()); if (!proxy_server.is_valid()) return; if (proxy_server.is_direct()) @@ -221,7 +221,7 @@ void DataReductionProxyRequestOptions::MaybeAddProxyTunnelRequestHandler( const net::HostPortPair& proxy_server, net::HttpRequestHeaders* request_headers) { - DCHECK(network_task_runner_->BelongsToCurrentThread()); + DCHECK(thread_checker_.CalledOnValidThread()); MaybeAddRequestHeaderImpl(proxy_server, true, request_headers); } @@ -273,6 +273,7 @@ } void DataReductionProxyRequestOptions::SetKeyOnIO(const std::string& key) { + DCHECK(thread_checker_.CalledOnValidThread()); if(!key.empty()) { key_ = key; UpdateCredentials(); @@ -281,7 +282,7 @@ void DataReductionProxyRequestOptions::PopulateConfigResponse( base::DictionaryValue* response) const { - DCHECK(network_task_runner_->BelongsToCurrentThread()); + DCHECK(thread_checker_.CalledOnValidThread()); std::string session; std::string credentials; base::Time now = Now(); @@ -296,7 +297,7 @@ void DataReductionProxyRequestOptions::SetCredentials( const std::string& session, const std::string& credentials) { - DCHECK(network_task_runner_->BelongsToCurrentThread()); + DCHECK(thread_checker_.CalledOnValidThread()); session_ = session; credentials_ = credentials; // Force skipping of credential regeneration. It should be handled by the
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 8d6c289..2aa8dce 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
@@ -9,13 +9,12 @@ #include <vector> #include "base/gtest_prod_util.h" -#include "base/memory/ref_counted.h" #include "base/strings/string16.h" +#include "base/threading/thread_checker.h" #include "base/time/time.h" namespace base { class DictionaryValue; -class SingleThreadTaskRunner; } namespace net { @@ -83,11 +82,9 @@ std::string* credentials); // Constructs a DataReductionProxyRequestOptions object with the given - // client type, config, and network task runner. - DataReductionProxyRequestOptions( - Client client, - DataReductionProxyConfig* config, - scoped_refptr<base::SingleThreadTaskRunner> network_task_runner); + // client type, and config. + DataReductionProxyRequestOptions(Client client, + DataReductionProxyConfig* config); virtual ~DataReductionProxyRequestOptions(); @@ -145,11 +142,9 @@ virtual std::string GetDefaultKey() const; // Visible for testing. - DataReductionProxyRequestOptions( - Client client, - const std::string& version, - DataReductionProxyConfig* config, - scoped_refptr<base::SingleThreadTaskRunner> network_task_runner); + DataReductionProxyRequestOptions(Client client, + const std::string& version, + DataReductionProxyConfig* config); private: FRIEND_TEST_ALL_PREFIXES(DataReductionProxyRequestOptionsTest, @@ -219,9 +214,11 @@ // |SetCredentials|. bool use_assigned_credentials_; + // Must outlive |this|. DataReductionProxyConfig* data_reduction_proxy_config_; - scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_; + // Enforce usage on the IO thread. + base::ThreadChecker thread_checker_; DISALLOW_COPY_AND_ASSIGN(DataReductionProxyRequestOptions); };
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 d34ebf2..95c3465 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
@@ -135,10 +135,8 @@ } void CreateRequestOptions(const std::string& version) { - request_options_.reset( - new TestDataReductionProxyRequestOptions( - kClient, version, test_context_->config(), - test_context_->task_runner())); + request_options_.reset(new TestDataReductionProxyRequestOptions( + kClient, version, test_context_->config())); request_options_->Init(); }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc index 91a71cb9..7d04b1e7 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc
@@ -13,7 +13,6 @@ #include "base/time/time.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.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_test_utils.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers_test_utils.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h index 5c6eef6..bfe3947 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h
@@ -23,7 +23,6 @@ namespace data_reduction_proxy { -class DataReductionProxyConfigurator; class DataReductionProxyTestContext; class MockDataReductionProxyConfig;
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 f479053a..921a99a 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
@@ -45,9 +45,8 @@ TestDataReductionProxyRequestOptions::TestDataReductionProxyRequestOptions( Client client, const std::string& version, - DataReductionProxyConfig* config, - scoped_refptr<base::SingleThreadTaskRunner> task_runner) - : DataReductionProxyRequestOptions(client, version, config, task_runner) { + DataReductionProxyConfig* config) + : DataReductionProxyRequestOptions(client, version, config) { } std::string TestDataReductionProxyRequestOptions::GetDefaultKey() const { @@ -75,9 +74,8 @@ MockDataReductionProxyRequestOptions::MockDataReductionProxyRequestOptions( Client client, const std::string& version, - DataReductionProxyConfig* config, - scoped_refptr<base::SingleThreadTaskRunner> task_runner) - : DataReductionProxyRequestOptions(client, version, config, task_runner) { + DataReductionProxyConfig* config) + : DataReductionProxyRequestOptions(client, version, config) { } MockDataReductionProxyRequestOptions::~MockDataReductionProxyRequestOptions() { @@ -88,14 +86,12 @@ scoped_ptr<DataReductionProxyParams> params, DataReductionProxyRequestOptions* request_options, DataReductionProxyMutableConfigValues* config_values, - DataReductionProxyConfig* config, - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) + DataReductionProxyConfig* config) : DataReductionProxyConfigServiceClient(params.Pass(), kTestBackoffPolicy, request_options, config_values, - config, - io_task_runner), + config), tick_clock_(base::Time::UnixEpoch()), test_backoff_entry_(&kTestBackoffPolicy, &tick_clock_) { } @@ -320,10 +316,10 @@ if (use_test_configurator_) { test_context_flags |= USE_TEST_CONFIGURATOR; configurator.reset(new TestDataReductionProxyConfigurator( - task_runner, net_log.get(), event_store.get())); + net_log.get(), event_store.get())); } else { - configurator.reset(new DataReductionProxyConfigurator( - task_runner, net_log.get(), event_store.get())); + configurator.reset( + new DataReductionProxyConfigurator(net_log.get(), event_store.get())); } scoped_ptr<TestDataReductionProxyConfig> config; @@ -335,8 +331,7 @@ if (use_config_client_) { test_context_flags |= USE_CONFIG_CLIENT; scoped_ptr<DataReductionProxyMutableConfigValues> mutable_config = - DataReductionProxyMutableConfigValues::CreateFromParams(task_runner, - params.get()); + DataReductionProxyMutableConfigValues::CreateFromParams(params.get()); raw_mutable_config = mutable_config.get(); config.reset(new TestDataReductionProxyConfig( mutable_config.Pass(), task_runner, net_log.get(), configurator.get(), @@ -356,21 +351,21 @@ if (use_mock_request_options_) { test_context_flags |= USE_MOCK_REQUEST_OPTIONS; request_options.reset(new MockDataReductionProxyRequestOptions( - client_, std::string(), config.get(), task_runner)); + client_, std::string(), config.get())); } else { - request_options.reset(new DataReductionProxyRequestOptions( - client_, config.get(), task_runner)); + request_options.reset( + new DataReductionProxyRequestOptions(client_, config.get())); } if (use_test_config_client_) { test_context_flags |= USE_TEST_CONFIG_CLIENT; config_client.reset(new TestDataReductionProxyConfigServiceClient( - params.Pass(), request_options.get(), raw_mutable_config, config.get(), - task_runner)); + params.Pass(), request_options.get(), raw_mutable_config, + config.get())); } else if (use_config_client_) { config_client.reset(new DataReductionProxyConfigServiceClient( params.Pass(), GetBackoffPolicy(), request_options.get(), - raw_mutable_config, config.get(), task_runner)); + raw_mutable_config, config.get())); } scoped_ptr<DataReductionProxySettings> settings(
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 5cc6dfb..7b2add4 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
@@ -53,11 +53,9 @@ class TestDataReductionProxyRequestOptions : public DataReductionProxyRequestOptions { public: - TestDataReductionProxyRequestOptions( - Client client, - const std::string& version, - DataReductionProxyConfig* config, - scoped_refptr<base::SingleThreadTaskRunner> task_runner); + TestDataReductionProxyRequestOptions(Client client, + const std::string& version, + DataReductionProxyConfig* config); // Overrides of DataReductionProxyRequestOptions. std::string GetDefaultKey() const override; @@ -75,11 +73,9 @@ class MockDataReductionProxyRequestOptions : public DataReductionProxyRequestOptions { public: - MockDataReductionProxyRequestOptions( - Client client, - const std::string& version, - DataReductionProxyConfig* config, - scoped_refptr<base::SingleThreadTaskRunner> task_runner); + MockDataReductionProxyRequestOptions(Client client, + const std::string& version, + DataReductionProxyConfig* config); ~MockDataReductionProxyRequestOptions(); @@ -96,8 +92,7 @@ scoped_ptr<DataReductionProxyParams> params, DataReductionProxyRequestOptions* request_options, DataReductionProxyMutableConfigValues* config_values, - DataReductionProxyConfig* config, - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner); + DataReductionProxyConfig* config); ~TestDataReductionProxyConfigServiceClient() override;
diff --git a/components/dom_distiller/android/BUILD.gn b/components/dom_distiller/android/BUILD.gn index 2cc4dc7..833b5da 100644 --- a/components/dom_distiller/android/BUILD.gn +++ b/components/dom_distiller/android/BUILD.gn
@@ -24,6 +24,7 @@ android_library("dom_distiller_content_java") { deps = [ ":dom_distiller_core_java", + "//base:base_java", "//content/public/android:content_java", ] java_files = [ "java/src/org/chromium/components/dom_distiller/content/DistillablePageUtils.java" ]
diff --git a/components/dom_distiller/content/distillable_page_utils.cc b/components/dom_distiller/content/distillable_page_utils.cc index 52029922..1267bfb 100644 --- a/components/dom_distiller/content/distillable_page_utils.cc +++ b/components/dom_distiller/content/distillable_page_utils.cc
@@ -51,9 +51,9 @@ void IsDistillablePage(content::WebContents* web_contents, base::Callback<void(bool)> callback) { switch (GetDistillerHeuristicsType()) { - case DistillerHeuristicsType::NONE: + case DistillerHeuristicsType::ALWAYS_TRUE: base::MessageLoop::current()->PostTask(FROM_HERE, - base::Bind(callback, false)); + base::Bind(callback, true)); return; case DistillerHeuristicsType::OG_ARTICLE: IsOpenGraphArticle(web_contents, callback); @@ -62,6 +62,11 @@ IsDistillablePageForDetector( web_contents, DistillablePageDetector::GetDefault(), callback); return; + case DistillerHeuristicsType::NONE: + default: + base::MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(callback, false)); + return; } }
diff --git a/components/dom_distiller/content/distiller_page_web_contents_browsertest.cc b/components/dom_distiller/content/distiller_page_web_contents_browsertest.cc index 2c84e6b..79d557a 100644 --- a/components/dom_distiller/content/distiller_page_web_contents_browsertest.cc +++ b/components/dom_distiller/content/distiller_page_web_contents_browsertest.cc
@@ -30,6 +30,46 @@ using testing::HasSubstr; using testing::Not; +namespace { + +// Helper class to know how far in the loading process the current WebContents +// has come. It will call the callback either after +// DidCommitProvisionalLoadForFrame or DocumentLoadedInFrame is called for the +// main frame, based on the value of |wait_for_document_loaded|. +class WebContentsMainFrameHelper : public content::WebContentsObserver { + public: + WebContentsMainFrameHelper(content::WebContents* web_contents, + const base::Closure& callback, + bool wait_for_document_loaded) + : WebContentsObserver(web_contents), + callback_(callback), + wait_for_document_loaded_(wait_for_document_loaded) {} + + void DidCommitProvisionalLoadForFrame( + content::RenderFrameHost* render_frame_host, + const GURL& url, + ui::PageTransition transition_type) override { + if (wait_for_document_loaded_) + return; + if (!render_frame_host->GetParent()) + callback_.Run(); + } + + void DocumentLoadedInFrame( + content::RenderFrameHost* render_frame_host) override { + if (wait_for_document_loaded_) { + if (!render_frame_host->GetParent()) + callback_.Run(); + } + } + + private: + base::Closure callback_; + bool wait_for_document_loaded_; +}; + +} // namespace + namespace dom_distiller { const char* kSimpleArticlePath = "/simple_article.html"; @@ -130,42 +170,6 @@ bool new_web_contents_created_; }; -// Helper class to know how far in the loading process the current WebContents -// has come. It will call the callback either after -// DidCommitProvisionalLoadForFrame or DocumentLoadedInFrame is called for the -// main frame, based on the value of |wait_for_document_loaded|. -class WebContentsMainFrameHelper : public content::WebContentsObserver { - public: - WebContentsMainFrameHelper(content::WebContents* web_contents, - const base::Closure& callback, - bool wait_for_document_loaded) - : WebContentsObserver(web_contents), - callback_(callback), - wait_for_document_loaded_(wait_for_document_loaded) {} - - void DidCommitProvisionalLoadForFrame( - content::RenderFrameHost* render_frame_host, - const GURL& url, - ui::PageTransition transition_type) override { - if (wait_for_document_loaded_) - return; - if (!render_frame_host->GetParent()) - callback_.Run(); - } - - void DocumentLoadedInFrame( - content::RenderFrameHost* render_frame_host) override { - if (wait_for_document_loaded_) { - if (!render_frame_host->GetParent()) - callback_.Run(); - } - } - - private: - base::Closure callback_; - bool wait_for_document_loaded_; -}; - IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest, BasicDistillationWorks) { DistillerPageWebContents distiller_page( shell()->web_contents()->GetBrowserContext(),
diff --git a/components/dom_distiller/content/test/dom_distiller_js_browsertest.cc b/components/dom_distiller/content/test/dom_distiller_js_browsertest.cc new file mode 100644 index 0000000..53b37b6 --- /dev/null +++ b/components/dom_distiller/content/test/dom_distiller_js_browsertest.cc
@@ -0,0 +1,160 @@ +// 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/callback.h" +#include "base/logging.h" +#include "base/message_loop/message_loop.h" +#include "base/path_service.h" +#include "base/run_loop.h" +#include "base/strings/utf_string_conversions.h" +#include "base/time/time.h" +#include "base/values.h" +#include "components/dom_distiller/content/web_contents_main_frame_observer.h" +#include "content/public/browser/navigation_controller.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/web_contents_observer.h" +#include "content/public/test/content_browser_test.h" +#include "content/shell/browser/shell.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "ui/base/resource/resource_bundle.h" + +namespace { + +// Helper class to know how far in the loading process the current WebContents +// has come. It will call the callback after DocumentLoadedInFrame is called for +// the main frame. +class WebContentsMainFrameHelper : public content::WebContentsObserver { + public: + WebContentsMainFrameHelper(content::WebContents* web_contents, + const base::Closure& callback) + : WebContentsObserver(web_contents), callback_(callback) {} + + void DocumentLoadedInFrame( + content::RenderFrameHost* render_frame_host) override { + if (!render_frame_host->GetParent()) + callback_.Run(); + } + + private: + base::Closure callback_; +}; + +} // namespace + +namespace dom_distiller { + +const char* kExternalTestResourcesPath = + "third_party/dom_distiller_js/dist/test/data"; +// TODO(wychen) Remove filter when crbug.com/471854 is fixed. +const char* kTestFilePath = + "/war/test.html?console_log=0&filter=-*.SchemaOrgParserAccessorTest.*"; +const char* kRunJsTestsJs = + "(function() {return org.chromium.distiller.JsTestEntry.run();})();"; + +class DomDistillerJsTest : public content::ContentBrowserTest { + public: + DomDistillerJsTest() : result_(NULL) {} + + // content::ContentBrowserTest: + void SetUpOnMainThread() override { + AddComponentsResources(); + SetUpTestServer(); + content::ContentBrowserTest::SetUpOnMainThread(); + } + + void OnJsTestExecutionDone(const base::Value* value) { + result_ = value->DeepCopy(); + js_test_execution_done_callback_.Run(); + } + + protected: + base::Closure js_test_execution_done_callback_; + const base::Value* result_; + + private: + void AddComponentsResources() { + base::FilePath pak_file; + base::FilePath pak_dir; + PathService::Get(base::DIR_MODULE, &pak_dir); + pak_file = pak_dir.Append(FILE_PATH_LITERAL("components_resources.pak")); + ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath( + pak_file, ui::SCALE_FACTOR_NONE); + } + + void SetUpTestServer() { + base::FilePath path; + PathService::Get(base::DIR_SOURCE_ROOT, &path); + path = path.AppendASCII(kExternalTestResourcesPath); + embedded_test_server()->ServeFilesFromDirectory(path); + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + } +}; + +IN_PROC_BROWSER_TEST_F(DomDistillerJsTest, RunJsTests) { + // Load the test file in content shell and wait until it has fully loaded. + content::WebContents* web_contents = shell()->web_contents(); + dom_distiller::WebContentsMainFrameObserver::CreateForWebContents( + web_contents); + base::RunLoop url_loaded_runner; + WebContentsMainFrameHelper main_frame_loaded(web_contents, + url_loaded_runner.QuitClosure()); + web_contents->GetController().LoadURL( + embedded_test_server()->GetURL(kTestFilePath), + content::Referrer(), + ui::PAGE_TRANSITION_TYPED, + std::string()); + url_loaded_runner.Run(); + + // Execute the JS to run the tests, and wait until it has finished. + base::RunLoop run_loop; + js_test_execution_done_callback_ = run_loop.QuitClosure(); + // Add timeout in case JS Test execution fails. It is safe to call the + // QuitClosure multiple times. + base::MessageLoop::current()->PostDelayedTask( + FROM_HERE, run_loop.QuitClosure(), base::TimeDelta::FromSeconds(15)); + web_contents->GetMainFrame()->ExecuteJavaScript( + base::UTF8ToUTF16(kRunJsTestsJs), + base::Bind(&DomDistillerJsTest::OnJsTestExecutionDone, + base::Unretained(this))); + run_loop.Run(); + + // By now either the timeout has triggered, or there should be a result. + ASSERT_TRUE(result_ != NULL) << "No result found. Timeout?"; + + // Convert to dictionary and parse the results. + const base::DictionaryValue* dict; + result_->GetAsDictionary(&dict); + ASSERT_TRUE(result_->GetAsDictionary(&dict)); + + ASSERT_TRUE(dict->HasKey("success")); + bool success; + ASSERT_TRUE(dict->GetBoolean("success", &success)); + + ASSERT_TRUE(dict->HasKey("numTests")); + int num_tests; + ASSERT_TRUE(dict->GetInteger("numTests", &num_tests)); + + ASSERT_TRUE(dict->HasKey("failed")); + int failed; + ASSERT_TRUE(dict->GetInteger("failed", &failed)); + + ASSERT_TRUE(dict->HasKey("skipped")); + int skipped; + ASSERT_TRUE(dict->GetInteger("skipped", &skipped)); + + VLOG(0) << "Ran " << num_tests << " tests. failed = " << failed + << " skipped = " << skipped; + // Ensure that running the tests succeeded. + EXPECT_TRUE(success); + + // Only print the log if there was an error. + if (!success) { + ASSERT_TRUE(dict->HasKey("log")); + std::string console_log; + ASSERT_TRUE(dict->GetString("log", &console_log)); + VLOG(0) << "Console log:\n" << console_log; + } +} + +} // namespace dom_distiller
diff --git a/components/dom_distiller/core/css/distilledpage.css b/components/dom_distiller/core/css/distilledpage.css index 13a3967a..adfb682 100644 --- a/components/dom_distiller/core/css/distilledpage.css +++ b/components/dom_distiller/core/css/distilledpage.css
@@ -308,19 +308,20 @@ } /* Footer feedback form. */ -.contentWrap { +#contentWrap { min-height: 100%; overflow: auto; padding-bottom: 120px; } .footerFeedback { + background-color: #4285F4; clear: both; + color: #fff; display: none; height: 120px; margin-top: -120px; - background-color: #4285F4; - color: #fff; + width: 100%; } .feedbackContent { @@ -363,15 +364,17 @@ /* Feedback fade out */ .fadeOut { animation-duration: 0.5s; - animation-name: fadeOutAnimation; + animation-name: fadeOutAndSwipeAnimation; } -@keyframes fadeOutAnimation { +@keyframes fadeOutAndSwipeAnimation { from { + margin-left: 0%; opacity: 1; } to { + margin-left: -100%; opacity: 0; } }
diff --git a/components/dom_distiller/core/dom_distiller_switches.cc b/components/dom_distiller/core/dom_distiller_switches.cc index ffb19d3..ad3d693 100644 --- a/components/dom_distiller/core/dom_distiller_switches.cc +++ b/components/dom_distiller/core/dom_distiller_switches.cc
@@ -9,4 +9,6 @@ "enable-reader-mode-og-article-heuristics"; const char kEnableReaderModeAdaBoostHeuristics[] = "enable-reader-mode-adaboost-heuristics"; +const char kEnableReaderModeAlwaysTrueHeuristics[] = + "enable-reader-mode-always-true-heuristics"; };
diff --git a/components/dom_distiller/core/dom_distiller_switches.h b/components/dom_distiller/core/dom_distiller_switches.h index fa632b6..ef8994b 100644 --- a/components/dom_distiller/core/dom_distiller_switches.h +++ b/components/dom_distiller/core/dom_distiller_switches.h
@@ -12,6 +12,7 @@ extern const char kEnableReaderModeOGArticleHeuristics[]; extern const char kEnableReaderModeAdaBoostHeuristics[]; +extern const char kEnableReaderModeAlwaysTrueHeuristics[]; };
diff --git a/components/dom_distiller/core/experiments.cc b/components/dom_distiller/core/experiments.cc index b84eb15..102b6d4 100644 --- a/components/dom_distiller/core/experiments.cc +++ b/components/dom_distiller/core/experiments.cc
@@ -14,8 +14,12 @@ const std::string group_name = base::FieldTrialList::FindFullName("ReaderModeUI"); if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableReaderModeOGArticleHeuristics) || - group_name == "OGArticle" || group_name == "ForcedOGArticle") { + switches::kEnableReaderModeAlwaysTrueHeuristics) || + group_name == "ForcedAlwaysTrue") { + return DistillerHeuristicsType::ALWAYS_TRUE; + } else if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableReaderModeOGArticleHeuristics) || + group_name == "OGArticle" || group_name == "ForcedOGArticle") { return DistillerHeuristicsType::OG_ARTICLE; } else if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableReaderModeAdaBoostHeuristics) ||
diff --git a/components/dom_distiller/core/experiments.h b/components/dom_distiller/core/experiments.h index 7f1f350f..16edfcb 100644 --- a/components/dom_distiller/core/experiments.h +++ b/components/dom_distiller/core/experiments.h
@@ -10,6 +10,7 @@ NONE, OG_ARTICLE, ADABOOST_MODEL, + ALWAYS_TRUE, }; DistillerHeuristicsType GetDistillerHeuristicsType();
diff --git a/components/dom_distiller/core/html/dom_distiller_viewer.html b/components/dom_distiller/core/html/dom_distiller_viewer.html index 02704ea..962df6a 100644 --- a/components/dom_distiller/core/html/dom_distiller_viewer.html +++ b/components/dom_distiller/core/html/dom_distiller_viewer.html
@@ -13,7 +13,7 @@ <link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'> </head> <body dir="$8" class="$4"> - <div class="contentWrap"> + <div id="contentWrap"> <div id="mainContent"> <article> <header id="articleHeader">
diff --git a/components/dom_distiller/core/javascript/dom_distiller_viewer.js b/components/dom_distiller/core/javascript/dom_distiller_viewer.js index 39d7f5c..78b67499 100644 --- a/components/dom_distiller/core/javascript/dom_distiller_viewer.js +++ b/components/dom_distiller/core/javascript/dom_distiller_viewer.js
@@ -156,6 +156,10 @@ document.getElementById('feedbackContainer').addEventListener('animationend', function(e) { - document.getElementById('feedbackContainer').style.display = "none"; + document.getElementById('feedbackContainer').style.display = 'none'; + // Close the gap where the feedback form was. + var contentWrap = document.getElementById('contentWrap'); + contentWrap.style.transition = '0.5s'; + contentWrap.style.paddingBottom = '0px'; }, true);
diff --git a/components/favicon/OWNERS b/components/favicon/OWNERS index 38c18f84..a5ad75c0 100644 --- a/components/favicon/OWNERS +++ b/components/favicon/OWNERS
@@ -1,5 +1,3 @@ +pkotwicz@chromium.org sky@chromium.org stevenjb@chromium.org - -# Temporary for the duration of the favicon componentization. -sdefresne@chromium.org
diff --git a/components/favicon/ios/OWNERS b/components/favicon/ios/OWNERS new file mode 100644 index 0000000..378261e88 --- /dev/null +++ b/components/favicon/ios/OWNERS
@@ -0,0 +1 @@ +sdefresne@chromium.org \ No newline at end of file
diff --git a/components/history/core/browser/expire_history_backend.cc b/components/history/core/browser/expire_history_backend.cc index 30eccf5..e39c272 100644 --- a/components/history/core/browser/expire_history_backend.cc +++ b/components/history/core/browser/expire_history_backend.cc
@@ -157,9 +157,15 @@ HistoryClient* history_client = GetHistoryClient(); for (std::vector<GURL>::const_iterator url = urls.begin(); url != urls.end(); ++url) { + const bool is_bookmarked = + history_client && history_client->IsBookmarked(*url); URLRow url_row; - if (!main_db_->GetRowForURL(*url, &url_row)) - continue; // Nothing to delete. + if (!main_db_->GetRowForURL(*url, &url_row) && !is_bookmarked) { + // If the URL isn't in the database and not bookmarked, we should still + // check to see if any favicons need to be deleted. + DeleteIcons(*url, &effects); + continue; + } // Collect all the visits and delete them. Note that we don't give up if // there are no visits, since the URL could still have an entry that we @@ -173,9 +179,7 @@ // URL, and not starting with visits in a given time range). We // therefore need to call the deletion and favicon update // functions manually. - DeleteOneURL(url_row, - history_client && history_client->IsBookmarked(*url), - &effects); + DeleteOneURL(url_row, is_bookmarked, &effects); } DeleteFaviconsIfPossible(&effects); @@ -346,25 +350,26 @@ bool is_bookmarked, DeleteEffects* effects) { main_db_->DeleteSegmentForURL(url_row.id()); + effects->deleted_urls.push_back(url_row); + // If the URL is bookmarked we should still keep its favicon around to show + // in bookmark-related UI. We'll delete this icon if the URL is unbookmarked. + // (See comments in DeleteURLs().) + if (!is_bookmarked) + DeleteIcons(url_row.url(), effects); + main_db_->DeleteURLRow(url_row.id()); +} - if (!is_bookmarked) { - effects->deleted_urls.push_back(url_row); - - // Delete stuff that references this URL. - if (thumb_db_) { - // Collect shared information. - std::vector<IconMapping> icon_mappings; - if (thumb_db_->GetIconMappingsForPageURL(url_row.url(), &icon_mappings)) { - for (std::vector<IconMapping>::iterator m = icon_mappings.begin(); - m != icon_mappings.end(); ++m) { - effects->affected_favicons.insert(m->icon_id); - } - // Delete the mapping entries for the url. - thumb_db_->DeleteIconMappings(url_row.url()); - } +void ExpireHistoryBackend::DeleteIcons(const GURL& gurl, + DeleteEffects* effects) { + // Collect shared information. + std::vector<IconMapping> icon_mappings; + if (thumb_db_ && thumb_db_->GetIconMappingsForPageURL(gurl, &icon_mappings)) { + for (std::vector<IconMapping>::iterator m = icon_mappings.begin(); + m != icon_mappings.end(); ++m) { + effects->affected_favicons.insert(m->icon_id); } - // Last, delete the URL entry. - main_db_->DeleteURLRow(url_row.id()); + // Delete the mapping entries for the url. + thumb_db_->DeleteIconMappings(gurl); } }
diff --git a/components/history/core/browser/expire_history_backend.h b/components/history/core/browser/expire_history_backend.h index ac70314..741b8620 100644 --- a/components/history/core/browser/expire_history_backend.h +++ b/components/history/core/browser/expire_history_backend.h
@@ -145,15 +145,16 @@ // // Assumes the main_db_ is non-NULL. // - // NOTE: If the url is bookmarked only the segments and text db are updated, - // everything else is unchanged. This is done so that bookmarks retain their - // favicons and thumbnails. + // NOTE: If the url is bookmarked, we keep the favicons and thumbnails. void DeleteOneURL(const URLRow& url_row, bool is_bookmarked, DeleteEffects* effects); + // Deletes all favicons associated with |gurl|. + void DeleteIcons(const GURL& gurl, DeleteEffects* effects); + // Deletes all the URLs in the given vector and handles their dependencies. - // This will delete starred URLs + // This will delete starred URLs. void DeleteURLs(const URLRows& urls, DeleteEffects* effects); // Expiration involves removing visits, then propagating the visits out from
diff --git a/components/history/core/browser/history_backend.cc b/components/history/core/browser/history_backend.cc index 4abcca4..6c28260 100644 --- a/components/history/core/browser/history_backend.cc +++ b/components/history/core/browser/history_backend.cc
@@ -2373,13 +2373,13 @@ return; for (std::set<GURL>::const_iterator i = urls.begin(); i != urls.end(); ++i) { - URLRow url_row; - if (!db_->GetRowForURL(*i, &url_row)) - continue; // The URL isn't in the db; nothing to do. - VisitVector visits; - db_->GetVisitsForURL(url_row.id(), &visits); - + URLRow url_row; + if (db_->GetRowForURL(*i, &url_row)) + db_->GetVisitsForURL(url_row.id(), &visits); + // We need to call DeleteURL() even if the DB didn't contain this URL, so + // that we can delete all associated icons in the case of deleting an + // unvisited bookmarked URL. if (visits.empty()) expirer_.DeleteURL(*i); // There are no more visits; nuke the URL. }
diff --git a/components/nacl/loader/nonsfi/nonsfi_sandbox.cc b/components/nacl/loader/nonsfi/nonsfi_sandbox.cc index 0340f6ff..2a6d5bc9 100644 --- a/components/nacl/loader/nonsfi/nonsfi_sandbox.cc +++ b/components/nacl/loader/nonsfi/nonsfi_sandbox.cc
@@ -10,7 +10,6 @@ #include <linux/net.h> #include <sys/mman.h> #include <sys/prctl.h> -#include <sys/ptrace.h> #include <sys/socket.h> #include <sys/syscall.h> #include <sys/time.h> @@ -185,7 +184,8 @@ void RunSandboxSanityChecks() { errno = 0; // Make a ptrace request with an invalid PID. - long ptrace_ret = ptrace(PTRACE_PEEKUSER, -1 /* pid */, NULL, NULL); + long ptrace_ret = syscall( + __NR_ptrace, 3 /* = PTRACE_PEEKUSER */, -1 /* pid */, NULL, NULL); CHECK_EQ(-1, ptrace_ret); // Without the sandbox on, this ptrace call would ESRCH instead. CHECK_EQ(EPERM, errno);
diff --git a/components/password_manager/core/browser/password_autofill_manager.cc b/components/password_manager/core/browser/password_autofill_manager.cc index 15d5f7e..e0a57cd 100644 --- a/components/password_manager/core/browser/password_autofill_manager.cc +++ b/components/password_manager/core/browser/password_autofill_manager.cc
@@ -218,9 +218,11 @@ autofill_client_->HideAutofillPopup(); } -void PasswordAutofillManager::RemoveSuggestion(const base::string16& value, +bool PasswordAutofillManager::RemoveSuggestion(const base::string16& value, int identifier) { - NOTREACHED(); + // http://crbug.com/329038 + NOTIMPLEMENTED(); + return false; } void PasswordAutofillManager::ClearPreviewedForm() {
diff --git a/components/password_manager/core/browser/password_autofill_manager.h b/components/password_manager/core/browser/password_autofill_manager.h index dfe0400..08c9842 100644 --- a/components/password_manager/core/browser/password_autofill_manager.h +++ b/components/password_manager/core/browser/password_autofill_manager.h
@@ -35,7 +35,7 @@ int identifier) override; void DidAcceptSuggestion(const base::string16& value, int identifier) override; - void RemoveSuggestion(const base::string16& value, int identifier) override; + bool RemoveSuggestion(const base::string16& value, int identifier) override; void ClearPreviewedForm() override; // Invoked when a password mapping is added.
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc index 64ade29c..88fdc57 100644 --- a/components/password_manager/core/browser/password_form_manager.cc +++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -16,6 +16,7 @@ #include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/browser/validation.h" #include "components/autofill/core/common/password_form.h" +#include "components/password_manager/core/browser/affiliation_utils.h" #include "components/password_manager/core/browser/browser_save_password_progress_logger.h" #include "components/password_manager/core/browser/password_manager.h" #include "components/password_manager/core/browser/password_manager_client.h" @@ -492,10 +493,15 @@ // Note that we provide the choices but don't actually prefill a value if: // (1) we are in Incognito mode, (2) the ACTION paths don't match, // or (3) if it matched using public suffix domain matching. - bool wait_for_username = client_->IsOffTheRecord() || - observed_form_.action.GetWithEmptyPath() != - preferred_match_->action.GetWithEmptyPath() || - preferred_match_->IsPublicSuffixMatch(); + // However, 2 and 3 should not apply to Android-based credentials found via + // affiliation-based matching (we want to autofill them). + // TODO(engedy): Clean this up. See: https://crbug.com/476519. + bool wait_for_username = + client_->IsOffTheRecord() || + (!IsValidAndroidFacetURI(preferred_match_->original_signon_realm) && + (observed_form_.action.GetWithEmptyPath() != + preferred_match_->action.GetWithEmptyPath() || + preferred_match_->IsPublicSuffixMatch())); if (wait_for_username) manager_action_ = kManagerActionNone; else
diff --git a/components/password_manager/core/browser/password_form_manager_unittest.cc b/components/password_manager/core/browser/password_form_manager_unittest.cc index 6d332db..7a20908 100644 --- a/components/password_manager/core/browser/password_form_manager_unittest.cc +++ b/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -129,7 +129,7 @@ class TestPasswordManager : public PasswordManager { public: explicit TestPasswordManager(TestPasswordManagerClient* client) - : PasswordManager(client) {} + : PasswordManager(client), wait_for_username_(false) {} void Autofill(password_manager::PasswordManagerDriver* driver, const autofill::PasswordForm& form_for_autofill, @@ -137,15 +137,21 @@ const autofill::PasswordForm& preferred_match, bool wait_for_username) const override { best_matches_ = best_matches; + wait_for_username_ = wait_for_username; } const autofill::PasswordFormMap& GetLatestBestMatches() { return best_matches_; } + bool GetLatestWaitForUsername() { return wait_for_username_; } + private: // Marked mutable to get around constness of Autofill(). + // TODO(vabr): This should be rewritten as a mock of PasswordManager, and the + // interesting arguments should be saved via GMock actions instead. mutable autofill::PasswordFormMap best_matches_; + mutable bool wait_for_username_; }; } // namespace @@ -1007,6 +1013,32 @@ ->second->original_signon_realm); } +TEST_F(PasswordFormManagerTest, AndroidCredentialsAreAutofilled) { + EXPECT_CALL(*(client()->mock_driver()), AllowPasswordGenerationForForm(_)); + + TestPasswordManager password_manager(client()); + PasswordFormManager manager(&password_manager, client(), client()->driver(), + *observed_form(), false); + + // Although Android-based credentials are treated similarly to PSL-matched + // credentials in most respects, they should be autofilled as opposed to be + // filled on username-select. + ScopedVector<PasswordForm> simulated_results; + simulated_results.push_back(new PasswordForm()); + simulated_results[0]->signon_realm = observed_form()->signon_realm; + simulated_results[0]->original_signon_realm = + "android://hash@com.google.android"; + simulated_results[0]->origin = observed_form()->origin; + simulated_results[0]->username_value = saved_match()->username_value; + simulated_results[0]->password_value = saved_match()->password_value; + + manager.SimulateFetchMatchingLoginsFromPasswordStore(); + manager.OnGetPasswordStoreResults(simulated_results.Pass()); + + EXPECT_EQ(1u, password_manager.GetLatestBestMatches().size()); + EXPECT_FALSE(password_manager.GetLatestWaitForUsername()); +} + TEST_F(PasswordFormManagerTest, InvalidActionURLsDoNotMatch) { PasswordFormManager manager(nullptr, client(), kNoDriver, *observed_form(), false);
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc index a10b7e8..f4cd0658 100644 --- a/components/password_manager/core/browser/password_store.cc +++ b/components/password_manager/core/browser/password_store.cc
@@ -75,11 +75,13 @@ void PasswordStore::SetAffiliatedMatchHelper( scoped_ptr<AffiliatedMatchHelper> helper) { - DCHECK(helper); - DCHECK(!affiliated_match_helper_); affiliated_match_helper_ = helper.Pass(); } +bool PasswordStore::HasAffiliatedMatchHelper() const { + return affiliated_match_helper_; +} + void PasswordStore::AddLogin(const PasswordForm& form) { CheckForEmptyUsernameAndPassword(form); ScheduleTask(base::Bind(&PasswordStore::AddLoginInternal, this, form));
diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h index b4ba7b4..852a51e 100644 --- a/components/password_manager/core/browser/password_store.h +++ b/components/password_manager/core/browser/password_store.h
@@ -68,11 +68,15 @@ // Sets the affiliation-based match |helper| that will be used by subsequent // GetLogins() calls to return credentials stored not only for the requested - // sign-on realm, but also for affiliated Android applications. The helper - // must already be initialized. Unless a |helper| is set, affiliation-based - // matching is disabled. + // sign-on realm, but also for affiliated Android applications. If |helper| is + // null, clears the the currently set helper if any. Unless a helper is set, + // affiliation-based matching is disabled. The passed |helper| must already be + // initialized if it is non-null. void SetAffiliatedMatchHelper(scoped_ptr<AffiliatedMatchHelper> helper); + // Returns whether or not an affiliation-based match helper is set. + bool HasAffiliatedMatchHelper() const; + // Adds the given PasswordForm to the secure password store asynchronously. virtual void AddLogin(const autofill::PasswordForm& form);
diff --git a/components/plugins/OWNERS b/components/plugins/OWNERS index 00985a81..21efaa10 100644 --- a/components/plugins/OWNERS +++ b/components/plugins/OWNERS
@@ -1 +1,2 @@ bauerb@chromium.org +tommycli@chromium.org
diff --git a/components/proximity_auth.gypi b/components/proximity_auth.gypi index fe5f3be2..c4e2503 100644 --- a/components/proximity_auth.gypi +++ b/components/proximity_auth.gypi
@@ -79,6 +79,9 @@ "proximity_auth/cryptauth/cryptauth_client.h", "proximity_auth/cryptauth/cryptauth_client_impl.cc", "proximity_auth/cryptauth/cryptauth_client_impl.h", + "proximity_auth/cryptauth/cryptauth_enroller.h", + "proximity_auth/cryptauth/cryptauth_enroller_impl.cc", + "proximity_auth/cryptauth/cryptauth_enroller_impl.h", "proximity_auth/cryptauth/cryptauth_enrollment_utils.cc", "proximity_auth/cryptauth/cryptauth_enrollment_utils.h", "proximity_auth/cryptauth/secure_message_delegate.cc", @@ -97,10 +100,13 @@ 'dependencies': [ 'cryptauth_proto', '../base/base.gyp:base', + '../testing/gmock.gyp:gmock', ], 'sources': [ "proximity_auth/cryptauth/fake_secure_message_delegate.cc", "proximity_auth/cryptauth/fake_secure_message_delegate.h", + "proximity_auth/cryptauth/mock_cryptauth_client.cc", + "proximity_auth/cryptauth/mock_cryptauth_client.h", ], 'export_dependent_settings': [ 'cryptauth_proto',
diff --git a/components/proximity_auth/cryptauth/BUILD.gn b/components/proximity_auth/cryptauth/BUILD.gn index bf255eb6..fcbf846 100644 --- a/components/proximity_auth/cryptauth/BUILD.gn +++ b/components/proximity_auth/cryptauth/BUILD.gn
@@ -14,6 +14,9 @@ "cryptauth_client.h", "cryptauth_client_impl.cc", "cryptauth_client_impl.h", + "cryptauth_enroller.h", + "cryptauth_enroller_impl.cc", + "cryptauth_enroller_impl.h", "cryptauth_enrollment_utils.cc", "cryptauth_enrollment_utils.h", "secure_message_delegate.cc", @@ -32,14 +35,19 @@ } source_set("test_support") { + testonly = true + sources = [ "fake_secure_message_delegate.cc", "fake_secure_message_delegate.h", + "mock_cryptauth_client.cc", + "mock_cryptauth_client.h", ] deps = [ ":cryptauth", "//base", + "//testing/gmock", ] public_deps = [ @@ -54,6 +62,7 @@ "cryptauth_access_token_fetcher_impl_unittest.cc", "cryptauth_api_call_flow_unittest.cc", "cryptauth_client_impl_unittest.cc", + "cryptauth_enroller_impl_unittest.cc", "fake_secure_message_delegate_unittest.cc", ]
diff --git a/components/proximity_auth/cryptauth/cryptauth_enroller.h b/components/proximity_auth/cryptauth/cryptauth_enroller.h new file mode 100644 index 0000000..99f7b04f --- /dev/null +++ b/components/proximity_auth/cryptauth/cryptauth_enroller.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 COMPONENTS_PROXIMITY_AUTH_CRYPTAUTH_ENROLLER_H +#define COMPONENTS_PROXIMITY_AUTH_CRYPTAUTH_ENROLLER_H + +#include <string> + +#include "base/callback_forward.h" +#include "components/proximity_auth/cryptauth/proto/cryptauth_api.pb.h" + +namespace proximity_auth { + +// Interface for enrolling a device with CryptAuth. +class CryptAuthEnroller { + public: + // Enrolls the device with |device_info| properties for a given + // |invocation_reason|. |callback| will be called with true if the enrollment + // succeeds and false otherwise. + typedef base::Callback<void(bool)> EnrollmentFinishedCallback; + virtual void Enroll(const cryptauth::GcmDeviceInfo& device_info, + cryptauth::InvocationReason invocation_reason, + const EnrollmentFinishedCallback& callback) = 0; +}; + +} // namespace proximity_auth + +#endif // COMPONENTS_PROXIMITY_AUTH_CRYPTAUTH_ENROLLER_H
diff --git a/components/proximity_auth/cryptauth/cryptauth_enroller_impl.cc b/components/proximity_auth/cryptauth/cryptauth_enroller_impl.cc new file mode 100644 index 0000000..729648d --- /dev/null +++ b/components/proximity_auth/cryptauth/cryptauth_enroller_impl.cc
@@ -0,0 +1,202 @@ +// 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/proximity_auth/cryptauth/cryptauth_enroller_impl.h" + +#include "base/bind.h" +#include "components/proximity_auth/cryptauth/cryptauth_client.h" +#include "components/proximity_auth/cryptauth/cryptauth_enrollment_utils.h" +#include "components/proximity_auth/cryptauth/secure_message_delegate.h" + +namespace proximity_auth { + +namespace { + +// A successful SetupEnrollment or FinishEnrollment response should contain this +// status string. +const char kResponseStatusOk[] = "OK"; + +// The name of the "gcmV1" protocol that the enrolling device supports. +const char kSupportedEnrollmentTypeGcmV1[] = "gcmV1"; + +// The version field of the GcmMetadata message. +const int kGCMMetadataVersion = 1; + +// Returns true if |device_info| contains the required fields for enrollment. +bool ValidateDeviceInfo(const cryptauth::GcmDeviceInfo& device_info) { + if (!device_info.has_user_public_key()) { + VLOG(1) << "Expected user_public_key field in GcmDeviceInfo."; + return false; + } + + if (!device_info.has_key_handle()) { + VLOG(1) << "Expected key_handle field in GcmDeviceInfo."; + return false; + } + + if (!device_info.has_long_device_id()) { + VLOG(1) << "Expected long_device_id field in GcmDeviceInfo."; + return false; + } + + if (!device_info.has_device_type()) { + VLOG(1) << "Expected device_type field in GcmDeviceInfo."; + return false; + } + + return true; +} + +// Creates the public metadata to put in the SecureMessage that is sent to the +// server with the FinishEnrollment request. +std::string CreateEnrollmentPublicMetadata() { + cryptauth::GcmMetadata metadata; + metadata.set_version(kGCMMetadataVersion); + metadata.set_type(cryptauth::MessageType::ENROLLMENT); + return metadata.SerializeAsString(); +} + +} // namespace + +CryptAuthEnrollerImpl::CryptAuthEnrollerImpl( + scoped_ptr<CryptAuthClientFactory> client_factory, + scoped_ptr<SecureMessageDelegate> secure_message_delegate_) + : client_factory_(client_factory.Pass()), + secure_message_delegate_(secure_message_delegate_.Pass()), + weak_ptr_factory_(this) { +} + +CryptAuthEnrollerImpl::~CryptAuthEnrollerImpl() { +} + +void CryptAuthEnrollerImpl::Enroll( + const cryptauth::GcmDeviceInfo& device_info, + cryptauth::InvocationReason invocation_reason, + const EnrollmentFinishedCallback& callback) { + if (!callback_.is_null()) { + VLOG(1) << "Enroll() already called. Do not reuse."; + callback.Run(false); + return; + } + + device_info_ = device_info; + invocation_reason_ = invocation_reason; + callback_ = callback; + + if (!ValidateDeviceInfo(device_info)) { + callback.Run(false); + return; + } + + secure_message_delegate_->GenerateKeyPair( + base::Bind(&CryptAuthEnrollerImpl::OnKeyPairGenerated, + weak_ptr_factory_.GetWeakPtr())); +} + +void CryptAuthEnrollerImpl::OnKeyPairGenerated(const std::string& public_key, + const std::string& private_key) { + session_public_key_ = public_key; + session_private_key_ = private_key; + + cryptauth_client_ = client_factory_->CreateInstance(); + cryptauth::SetupEnrollmentRequest request; + request.add_types(kSupportedEnrollmentTypeGcmV1); + request.set_invocation_reason(invocation_reason_); + cryptauth_client_->SetupEnrollment( + request, base::Bind(&CryptAuthEnrollerImpl::OnSetupEnrollmentSuccess, + weak_ptr_factory_.GetWeakPtr()), + base::Bind(&CryptAuthEnrollerImpl::OnSetupEnrollmentFailure, + weak_ptr_factory_.GetWeakPtr())); +} + +void CryptAuthEnrollerImpl::OnSetupEnrollmentSuccess( + const cryptauth::SetupEnrollmentResponse& response) { + if (response.status() != kResponseStatusOk) { + VLOG(1) << "Unexpected status for SetupEnrollment: " << response.status(); + callback_.Run(false); + return; + } + + if (response.infos_size() == 0) { + VLOG(1) << "No response info returned by server for SetupEnrollment"; + callback_.Run(false); + return; + } + + setup_info_ = response.infos(0); + device_info_.set_enrollment_session_id(setup_info_.enrollment_session_id()); + secure_message_delegate_->DeriveKey( + session_private_key_, setup_info_.server_ephemeral_key(), + base::Bind(&CryptAuthEnrollerImpl::OnKeyDerived, + weak_ptr_factory_.GetWeakPtr())); +} + +void CryptAuthEnrollerImpl::OnSetupEnrollmentFailure(const std::string& error) { + VLOG(1) << "SetupEnrollment API failed with error: " << error; + callback_.Run(false); +} + +void CryptAuthEnrollerImpl::OnKeyDerived(const std::string& symmetric_key) { + symmetric_key_ = symmetric_key; + SecureMessageDelegate::CreateOptions options; + options.encryption_scheme = securemessage::NONE; + options.signature_scheme = securemessage::ECDSA_P256_SHA256; + options.verification_key_id = session_public_key_; + + // The inner message contains the signed device information that will be + // sent to CryptAuth. + secure_message_delegate_->CreateSecureMessage( + device_info_.SerializeAsString(), session_private_key_, options, + base::Bind(&CryptAuthEnrollerImpl::OnInnerSecureMessageCreated, + weak_ptr_factory_.GetWeakPtr())); +} + +void CryptAuthEnrollerImpl::OnInnerSecureMessageCreated( + const std::string& inner_message) { + SecureMessageDelegate::CreateOptions options; + options.encryption_scheme = securemessage::AES_256_CBC; + options.signature_scheme = securemessage::HMAC_SHA256; + options.public_metadata = CreateEnrollmentPublicMetadata(); + + // The outer message encrypts and signs the inner message with the derived + // symmetric session key. + secure_message_delegate_->CreateSecureMessage( + inner_message, symmetric_key_, options, + base::Bind(&CryptAuthEnrollerImpl::OnOuterSecureMessageCreated, + weak_ptr_factory_.GetWeakPtr())); +} + +void CryptAuthEnrollerImpl::OnOuterSecureMessageCreated( + const std::string& outer_message) { + cryptauth::FinishEnrollmentRequest request; + request.set_enrollment_session_id(setup_info_.enrollment_session_id()); + request.set_enrollment_message(outer_message); + request.set_device_ephemeral_key(session_public_key_); + request.set_invocation_reason(invocation_reason_); + + cryptauth_client_ = client_factory_->CreateInstance(); + cryptauth_client_->FinishEnrollment( + request, base::Bind(&CryptAuthEnrollerImpl::OnFinishEnrollmentSuccess, + weak_ptr_factory_.GetWeakPtr()), + base::Bind(&CryptAuthEnrollerImpl::OnFinishEnrollmentFailure, + weak_ptr_factory_.GetWeakPtr())); +} + +void CryptAuthEnrollerImpl::OnFinishEnrollmentSuccess( + const cryptauth::FinishEnrollmentResponse& response) { + if (response.status() != kResponseStatusOk) { + VLOG(1) << "Unexpected status for FinishEnrollment: " << response.status(); + callback_.Run(false); + } else { + callback_.Run(true); + } +} + +void CryptAuthEnrollerImpl::OnFinishEnrollmentFailure( + const std::string& error) { + VLOG(1) << "FinishEnrollment API failed with error: " << error; + callback_.Run(false); +} + +} // namespace proximity_auth
diff --git a/components/proximity_auth/cryptauth/cryptauth_enroller_impl.h b/components/proximity_auth/cryptauth/cryptauth_enroller_impl.h new file mode 100644 index 0000000..07da5ed --- /dev/null +++ b/components/proximity_auth/cryptauth/cryptauth_enroller_impl.h
@@ -0,0 +1,95 @@ +// 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_PROXIMITY_AUTH_CRYPTAUTH_ENROLLER_IMPL_H +#define COMPONENTS_PROXIMITY_AUTH_CRYPTAUTH_ENROLLER_IMPL_H + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "components/proximity_auth/cryptauth/cryptauth_enroller.h" + +namespace proximity_auth { + +class CryptAuthClient; +class CryptAuthClientFactory; +class SecureMessageDelegate; + +// Implementation of CryptAuthEnroller to perform enrollment in two steps: +// 1. SetupEnrollment: +// Obtain a session public key from CryptAuth used to encrypt enrollment +// data. Generate an ephemeral public key and derive a session symmetric +// key. +// 2. FinishEnrollment: +// Encrypt the enrollment data with the session symmetric key, and send the +// payload and device's public key to CryptAuth. +class CryptAuthEnrollerImpl : public CryptAuthEnroller { + public: + // |client_factory| creates CryptAuthClient instances for making API calls. + // |crypto_delegate| is responsible for SecureMessage operations. + CryptAuthEnrollerImpl( + scoped_ptr<CryptAuthClientFactory> client_factory, + scoped_ptr<SecureMessageDelegate> secure_message_delegate_); + ~CryptAuthEnrollerImpl(); + + // CryptAuthEnroller: + void Enroll(const cryptauth::GcmDeviceInfo& device_info, + cryptauth::InvocationReason invocation_reason, + const EnrollmentFinishedCallback& callback) override; + + private: + // Callbacks for SetupEnrollment. + void OnSetupEnrollmentSuccess( + const cryptauth::SetupEnrollmentResponse& response); + void OnSetupEnrollmentFailure(const std::string& error); + + // Callbacks for FinishEnrollment. + void OnFinishEnrollmentSuccess( + const cryptauth::FinishEnrollmentResponse& response); + void OnFinishEnrollmentFailure(const std::string& error); + + // Callbacks for SecureMessageDelegate operations. + void OnKeyPairGenerated(const std::string& public_key, + const std::string& private_key); + void OnKeyDerived(const std::string& symmetric_key); + void OnInnerSecureMessageCreated(const std::string& inner_message); + void OnOuterSecureMessageCreated(const std::string& outer_message); + + // Creates the CryptAuthClient instances to make API requests. + scoped_ptr<CryptAuthClientFactory> client_factory_; + + // Handles SecureMessage operations. + scoped_ptr<SecureMessageDelegate> secure_message_delegate_; + + // The CryptAuthClient for the latest request. + scoped_ptr<CryptAuthClient> cryptauth_client_; + + // The ephemeral key-pair generated for a single enrollment. + std::string session_public_key_; + std::string session_private_key_; + + // Contains information of the device to enroll. + cryptauth::GcmDeviceInfo device_info_; + + // The reason telling the server why the enrollment happened. + cryptauth::InvocationReason invocation_reason_; + + // The setup information returned from the SetupEnrollment API call. + cryptauth::SetupEnrollmentInfo setup_info_; + + // Callback invoked when the enrollment is done. + EnrollmentFinishedCallback callback_; + + // The derived ephemeral symmetric key. + std::string symmetric_key_; + + base::WeakPtrFactory<CryptAuthEnrollerImpl> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(CryptAuthEnrollerImpl); +}; + +} // namespace proximity_auth + +#endif // COMPONENTS_PROXIMITY_AUTH_CRYPTAUTH_ENROLLER_IMPL_H
diff --git a/components/proximity_auth/cryptauth/cryptauth_enroller_impl_unittest.cc b/components/proximity_auth/cryptauth/cryptauth_enroller_impl_unittest.cc new file mode 100644 index 0000000..bee79e43 --- /dev/null +++ b/components/proximity_auth/cryptauth/cryptauth_enroller_impl_unittest.cc
@@ -0,0 +1,338 @@ +// 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/proximity_auth/cryptauth/cryptauth_enroller_impl.h" + +#include "base/bind.h" +#include "components/proximity_auth/cryptauth/cryptauth_enrollment_utils.h" +#include "components/proximity_auth/cryptauth/fake_secure_message_delegate.h" +#include "components/proximity_auth/cryptauth/mock_cryptauth_client.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::_; + +namespace proximity_auth { + +namespace { + +const char kClientSessionPublicKey[] = "throw away after one use"; +const char kServerSessionPublicKey[] = "disposables are not eco-friendly"; +const char kClientPersistentPublicKey[] = "saves 50 trees a year"; + +cryptauth::InvocationReason kInvocationReason = + cryptauth::INVOCATION_REASON_MANUAL; +const int kGCMMetadataVersion = 1; +const char kSupportedEnrollmentTypeGcmV1[] = "gcmV1"; +const char kResponseStatusOk[] = "OK"; +const char kResponseStatusNotOk[] = "Your key was too bland."; +const char kEnrollmentSessionId[] = "0123456789876543210"; +const char kFinishEnrollmentError[] = "A hungry router ate all your packets."; + +const char kDeviceId[] = "2015 AD"; +const cryptauth::DeviceType kDeviceType = cryptauth::CHROME; +const char kDeviceOsVersion[] = "41.0.0"; + +// Creates and returns the GcmDeviceInfo message to be uploaded. +cryptauth::GcmDeviceInfo GetDeviceInfo() { + cryptauth::GcmDeviceInfo device_info; + device_info.set_long_device_id(kDeviceId); + device_info.set_device_type(kDeviceType); + device_info.set_device_os_version(kDeviceOsVersion); + device_info.set_user_public_key(kClientPersistentPublicKey); + device_info.set_key_handle(kClientPersistentPublicKey); + return device_info; +} + +// Creates and returns the SetupEnrollmentResponse message to be returned to the +// enroller with the session_. If |success| is false, then a bad response will +// be returned. +cryptauth::SetupEnrollmentResponse GetSetupEnrollmentResponse(bool success) { + cryptauth::SetupEnrollmentResponse response; + if (!success) { + response.set_status(kResponseStatusNotOk); + return response; + } + + response.set_status(kResponseStatusOk); + cryptauth::SetupEnrollmentInfo* info = response.add_infos(); + info->set_type(kSupportedEnrollmentTypeGcmV1); + info->set_enrollment_session_id(kEnrollmentSessionId); + info->set_server_ephemeral_key(kServerSessionPublicKey); + return response; +} + +// Creates and returns the FinishEnrollmentResponse message to be returned to +// the enroller with the session_. If |success| is false, then a bad response +// will be returned. +cryptauth::FinishEnrollmentResponse GetFinishEnrollmentResponse(bool success) { + cryptauth::FinishEnrollmentResponse response; + if (success) { + response.set_status(kResponseStatusOk); + } else { + response.set_status(kResponseStatusNotOk); + response.set_error_message(kFinishEnrollmentError); + } + return response; +} + +// Callback that saves the key returned by SecureMessageDelegate::DeriveKey(). +void SaveDerivedKey(std::string* value_out, const std::string& value) { + *value_out = value; +} + +// Callback that saves the results returned by +// SecureMessageDelegate::UnwrapSecureMessage(). +void SaveUnwrapResults(bool* verified_out, + std::string* payload_out, + securemessage::Header* header_out, + bool verified, + const std::string& payload, + const securemessage::Header& header) { + *verified_out = verified; + *payload_out = payload; + *header_out = header; +} + +} // namespace + +class ProximityAuthCryptAuthEnrollerTest + : public testing::Test, + public MockCryptAuthClientFactory::Observer { + public: + ProximityAuthCryptAuthEnrollerTest() + : client_factory_(new MockCryptAuthClientFactory(false)), + secure_message_delegate_(new FakeSecureMessageDelegate()), + enroller_(make_scoped_ptr(client_factory_), + make_scoped_ptr(secure_message_delegate_)) { + client_factory_->AddObserver(this); + } + + // Starts the enroller. + void StartEnroller(const cryptauth::GcmDeviceInfo& device_info) { + secure_message_delegate_->set_next_public_key(kClientSessionPublicKey); + enroller_result_.reset(); + enroller_.Enroll( + device_info, kInvocationReason, + base::Bind(&ProximityAuthCryptAuthEnrollerTest::OnEnrollerCompleted, + base::Unretained(this))); + } + + // Verifies that |serialized_message| is a valid SecureMessage sent with the + // FinishEnrollment API call. + void ValidateEnrollmentMessage(const std::string& serialized_message) { + // Derive the session symmetric key. + std::string server_session_private_key = + secure_message_delegate_->GetPrivateKeyForPublicKey( + kServerSessionPublicKey); + std::string symmetric_key; + secure_message_delegate_->DeriveKey( + server_session_private_key, kClientSessionPublicKey, + base::Bind(&SaveDerivedKey, &symmetric_key)); + + std::string inner_message; + std::string inner_payload; + { + // Unwrap the outer message. + bool verified; + securemessage::Header header; + SecureMessageDelegate::UnwrapOptions unwrap_options; + unwrap_options.encryption_scheme = securemessage::AES_256_CBC; + unwrap_options.signature_scheme = securemessage::HMAC_SHA256; + secure_message_delegate_->UnwrapSecureMessage( + serialized_message, symmetric_key, unwrap_options, + base::Bind(&SaveUnwrapResults, &verified, &inner_message, &header)); + EXPECT_TRUE(verified); + + cryptauth::GcmMetadata metadata; + ASSERT_TRUE(metadata.ParseFromString(header.public_metadata())); + EXPECT_EQ(kGCMMetadataVersion, metadata.version()); + EXPECT_EQ(cryptauth::MessageType::ENROLLMENT, metadata.type()); + } + + { + // Unwrap inner message. + bool verified; + securemessage::Header header; + SecureMessageDelegate::UnwrapOptions unwrap_options; + unwrap_options.encryption_scheme = securemessage::NONE; + unwrap_options.signature_scheme = securemessage::ECDSA_P256_SHA256; + secure_message_delegate_->UnwrapSecureMessage( + inner_message, kClientSessionPublicKey, unwrap_options, + base::Bind(&SaveUnwrapResults, &verified, &inner_payload, &header)); + EXPECT_TRUE(verified); + EXPECT_EQ(kClientSessionPublicKey, header.verification_key_id()); + } + + // Check that the decrypted GcmDeviceInfo is correct. + cryptauth::GcmDeviceInfo device_info; + ASSERT_TRUE(device_info.ParseFromString(inner_payload)); + EXPECT_EQ(kDeviceId, device_info.long_device_id()); + EXPECT_EQ(kDeviceType, device_info.device_type()); + EXPECT_EQ(kDeviceOsVersion, device_info.device_os_version()); + EXPECT_EQ(kClientPersistentPublicKey, device_info.user_public_key()); + EXPECT_EQ(kClientPersistentPublicKey, device_info.key_handle()); + EXPECT_EQ(kEnrollmentSessionId, device_info.enrollment_session_id()); + } + + protected: + // MockCryptAuthClientFactory::Observer: + void OnCryptAuthClientCreated(MockCryptAuthClient* client) override { + ON_CALL(*client, SetupEnrollment(_, _, _)) + .WillByDefault(Invoke( + this, &ProximityAuthCryptAuthEnrollerTest::OnSetupEnrollment)); + + ON_CALL(*client, FinishEnrollment(_, _, _)) + .WillByDefault(Invoke( + this, &ProximityAuthCryptAuthEnrollerTest::OnFinishEnrollment)); + } + + void OnEnrollerCompleted(bool success) { + EXPECT_FALSE(enroller_result_.get()); + enroller_result_.reset(new bool(success)); + } + + void OnSetupEnrollment( + const cryptauth::SetupEnrollmentRequest& request, + const CryptAuthClient::SetupEnrollmentCallback& callback, + const CryptAuthClient::ErrorCallback& error_callback) { + // Check that SetupEnrollment is called before FinishEnrollment. + EXPECT_FALSE(setup_request_.get()); + EXPECT_FALSE(finish_request_.get()); + EXPECT_TRUE(setup_callback_.is_null()); + EXPECT_TRUE(error_callback_.is_null()); + + setup_request_.reset(new cryptauth::SetupEnrollmentRequest(request)); + setup_callback_ = callback; + error_callback_ = error_callback; + } + + void OnFinishEnrollment( + const cryptauth::FinishEnrollmentRequest& request, + const CryptAuthClient::FinishEnrollmentCallback& callback, + const CryptAuthClient::ErrorCallback& error_callback) { + // Check that FinishEnrollment is called after SetupEnrollment. + EXPECT_TRUE(setup_request_.get()); + EXPECT_FALSE(finish_request_.get()); + EXPECT_TRUE(finish_callback_.is_null()); + + finish_request_.reset(new cryptauth::FinishEnrollmentRequest(request)); + finish_callback_ = callback; + error_callback_ = error_callback; + } + + // Owned by |enroller_|. + MockCryptAuthClientFactory* client_factory_; + // Owned by |enroller_|. + FakeSecureMessageDelegate* secure_message_delegate_; + // The CryptAuthEnroller under test. + CryptAuthEnrollerImpl enroller_; + + // Stores the result of running |enroller_|. + scoped_ptr<bool> enroller_result_; + + // Stored callbacks and requests for SetupEnrollment and FinishEnrollment. + scoped_ptr<cryptauth::SetupEnrollmentRequest> setup_request_; + scoped_ptr<cryptauth::FinishEnrollmentRequest> finish_request_; + CryptAuthClient::SetupEnrollmentCallback setup_callback_; + CryptAuthClient::FinishEnrollmentCallback finish_callback_; + CryptAuthClient::ErrorCallback error_callback_; + + DISALLOW_COPY_AND_ASSIGN(ProximityAuthCryptAuthEnrollerTest); +}; + +TEST_F(ProximityAuthCryptAuthEnrollerTest, EnrollmentSucceeds) { + StartEnroller(GetDeviceInfo()); + + // Handle SetupEnrollment request. + EXPECT_TRUE(setup_request_.get()); + EXPECT_EQ(kInvocationReason, setup_request_->invocation_reason()); + ASSERT_EQ(1, setup_request_->types_size()); + EXPECT_EQ(kSupportedEnrollmentTypeGcmV1, setup_request_->types(0)); + ASSERT_FALSE(setup_callback_.is_null()); + setup_callback_.Run(GetSetupEnrollmentResponse(true)); + + // Handle FinishEnrollment request. + EXPECT_TRUE(finish_request_.get()); + EXPECT_EQ(kEnrollmentSessionId, finish_request_->enrollment_session_id()); + EXPECT_EQ(kClientSessionPublicKey, finish_request_->device_ephemeral_key()); + ValidateEnrollmentMessage(finish_request_->enrollment_message()); + EXPECT_EQ(kInvocationReason, finish_request_->invocation_reason()); + + ASSERT_FALSE(finish_callback_.is_null()); + finish_callback_.Run(GetFinishEnrollmentResponse(true)); + + ASSERT_TRUE(enroller_result_.get()); + EXPECT_TRUE(*enroller_result_); +} + +TEST_F(ProximityAuthCryptAuthEnrollerTest, SetupEnrollmentApiCallError) { + StartEnroller(GetDeviceInfo()); + + EXPECT_TRUE(setup_request_.get()); + ASSERT_FALSE(error_callback_.is_null()); + error_callback_.Run("Setup enrollment failed network"); + + EXPECT_TRUE(finish_callback_.is_null()); + ASSERT_TRUE(enroller_result_.get()); + EXPECT_FALSE(*enroller_result_); +} + +TEST_F(ProximityAuthCryptAuthEnrollerTest, SetupEnrollmentBadStatus) { + StartEnroller(GetDeviceInfo()); + + EXPECT_TRUE(setup_request_.get()); + setup_callback_.Run(GetSetupEnrollmentResponse(false)); + + EXPECT_TRUE(finish_callback_.is_null()); + ASSERT_TRUE(enroller_result_.get()); + EXPECT_FALSE(*enroller_result_); +} + +TEST_F(ProximityAuthCryptAuthEnrollerTest, SetupEnrollmentNoInfosReturned) { + StartEnroller(GetDeviceInfo()); + EXPECT_TRUE(setup_request_.get()); + cryptauth::SetupEnrollmentResponse response; + response.set_status(kResponseStatusOk); + setup_callback_.Run(response); + + EXPECT_TRUE(finish_callback_.is_null()); + ASSERT_TRUE(enroller_result_.get()); + EXPECT_FALSE(*enroller_result_); +} + +TEST_F(ProximityAuthCryptAuthEnrollerTest, FinishEnrollmentApiCallError) { + StartEnroller(GetDeviceInfo()); + setup_callback_.Run(GetSetupEnrollmentResponse(true)); + ASSERT_FALSE(error_callback_.is_null()); + error_callback_.Run("finish enrollment oauth error"); + ASSERT_TRUE(enroller_result_.get()); + EXPECT_FALSE(*enroller_result_); +} + +TEST_F(ProximityAuthCryptAuthEnrollerTest, FinishEnrollmentBadStatus) { + StartEnroller(GetDeviceInfo()); + setup_callback_.Run(GetSetupEnrollmentResponse(true)); + ASSERT_FALSE(finish_callback_.is_null()); + finish_callback_.Run(GetFinishEnrollmentResponse(false)); + ASSERT_TRUE(enroller_result_.get()); + EXPECT_FALSE(*enroller_result_); +} + +TEST_F(ProximityAuthCryptAuthEnrollerTest, ReuseEnroller) { + StartEnroller(GetDeviceInfo()); + setup_callback_.Run(GetSetupEnrollmentResponse(true)); + finish_callback_.Run(GetFinishEnrollmentResponse(true)); + EXPECT_TRUE(*enroller_result_); + + StartEnroller(GetDeviceInfo()); + EXPECT_FALSE(*enroller_result_); +} + +TEST_F(ProximityAuthCryptAuthEnrollerTest, IncompleteDeviceInfo) { + StartEnroller(cryptauth::GcmDeviceInfo()); + ASSERT_TRUE(enroller_result_.get()); + EXPECT_FALSE(*enroller_result_); +} + +} // namespace proximity_auth
diff --git a/components/proximity_auth/cryptauth/fake_secure_message_delegate.cc b/components/proximity_auth/cryptauth/fake_secure_message_delegate.cc index 195c24b..5fa5c5f 100644 --- a/components/proximity_auth/cryptauth/fake_secure_message_delegate.cc +++ b/components/proximity_auth/cryptauth/fake_secure_message_delegate.cc
@@ -189,4 +189,9 @@ } } +std::string FakeSecureMessageDelegate::GetPrivateKeyForPublicKey( + const std::string& public_key) { + return kPrivateKeyPrefix + public_key; +} + } // namespace proximity_auth
diff --git a/components/proximity_auth/cryptauth/fake_secure_message_delegate.h b/components/proximity_auth/cryptauth/fake_secure_message_delegate.h index ad8b21b4..1fe9c0a 100644 --- a/components/proximity_auth/cryptauth/fake_secure_message_delegate.h +++ b/components/proximity_auth/cryptauth/fake_secure_message_delegate.h
@@ -34,6 +34,9 @@ const UnwrapOptions& unwrap_options, const UnwrapSecureMessageCallback& callback) override; + // Returns the corresponding private key for the given |public_key|. + std::string GetPrivateKeyForPublicKey(const std::string& public_key); + // Sets the next public key to be returned by GenerateKeyPair(). The // corresponding private key will be derived from this public key. void set_next_public_key(const std::string& public_key) {
diff --git a/components/proximity_auth/cryptauth/fake_secure_message_delegate_unittest.cc b/components/proximity_auth/cryptauth/fake_secure_message_delegate_unittest.cc index 12a02cd..6c35a7fe 100644 --- a/components/proximity_auth/cryptauth/fake_secure_message_delegate_unittest.cc +++ b/components/proximity_auth/cryptauth/fake_secure_message_delegate_unittest.cc
@@ -193,4 +193,13 @@ EXPECT_EQ(kPayload, payload); } +TEST_F(ProximityAuthFakeSecureMessageDelegateTest, GetPrivateKeyForPublicKey) { + delegate_.set_next_public_key(kTestPublicKey); + std::string public_key, private_key; + delegate_.GenerateKeyPair( + base::Bind(&SaveKeyPair, &public_key, &private_key)); + EXPECT_EQ(kTestPublicKey, public_key); + EXPECT_EQ(private_key, delegate_.GetPrivateKeyForPublicKey(kTestPublicKey)); +} + } // proximity_auth
diff --git a/components/proximity_auth/cryptauth/mock_cryptauth_client.cc b/components/proximity_auth/cryptauth/mock_cryptauth_client.cc new file mode 100644 index 0000000..099082fc --- /dev/null +++ b/components/proximity_auth/cryptauth/mock_cryptauth_client.cc
@@ -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. + +#include "base/callback.h" +#include "components/proximity_auth/cryptauth/mock_cryptauth_client.h" + +namespace proximity_auth { + +MockCryptAuthClient::MockCryptAuthClient() { +} + +MockCryptAuthClient::~MockCryptAuthClient() { +} + +MockCryptAuthClientFactory::MockCryptAuthClientFactory(bool is_strict) + : is_strict_(is_strict) { +} + +MockCryptAuthClientFactory::~MockCryptAuthClientFactory() { +} + +scoped_ptr<CryptAuthClient> MockCryptAuthClientFactory::CreateInstance() { + scoped_ptr<MockCryptAuthClient> client; + if (is_strict_) + client.reset(new testing::StrictMock<MockCryptAuthClient>()); + else + client.reset(new testing::NiceMock<MockCryptAuthClient>()); + + FOR_EACH_OBSERVER(Observer, observer_list_, + OnCryptAuthClientCreated(client.get())); + return client.Pass(); +} + +void MockCryptAuthClientFactory::AddObserver(Observer* observer) { + observer_list_.AddObserver(observer); +} + +void MockCryptAuthClientFactory::RemoveObserver(Observer* observer) { + observer_list_.RemoveObserver(observer); +} + +} // namespace proximity_auth
diff --git a/components/proximity_auth/cryptauth/mock_cryptauth_client.h b/components/proximity_auth/cryptauth/mock_cryptauth_client.h new file mode 100644 index 0000000..de818ecf --- /dev/null +++ b/components/proximity_auth/cryptauth/mock_cryptauth_client.h
@@ -0,0 +1,83 @@ +// 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_PROXIMITY_AUTH_MOCK_CRYPTAUTH_CLIENT_H +#define COMPONENTS_PROXIMITY_AUTH_MOCK_CRYPTAUTH_CLIENT_H + +#include "base/macros.h" +#include "base/observer_list.h" +#include "components/proximity_auth/cryptauth/cryptauth_client.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace proximity_auth { + +class MockCryptAuthClient : public CryptAuthClient { + public: + MockCryptAuthClient(); + ~MockCryptAuthClient() override; + + // CryptAuthClient: + MOCK_METHOD3(GetMyDevices, + void(const cryptauth::GetMyDevicesRequest& request, + const GetMyDevicesCallback& callback, + const ErrorCallback& error_callback)); + MOCK_METHOD3(FindEligibleUnlockDevices, + void(const cryptauth::FindEligibleUnlockDevicesRequest& request, + const FindEligibleUnlockDevicesCallback& callback, + const ErrorCallback& error_callback)); + MOCK_METHOD3(SendDeviceSyncTickle, + void(const cryptauth::SendDeviceSyncTickleRequest& request, + const SendDeviceSyncTickleCallback& callback, + const ErrorCallback& error_callback)); + MOCK_METHOD3(ToggleEasyUnlock, + void(const cryptauth::ToggleEasyUnlockRequest& request, + const ToggleEasyUnlockCallback& callback, + const ErrorCallback& error_callback)); + MOCK_METHOD3(SetupEnrollment, + void(const cryptauth::SetupEnrollmentRequest& request, + const SetupEnrollmentCallback& callback, + const ErrorCallback& error_callback)); + MOCK_METHOD3(FinishEnrollment, + void(const cryptauth::FinishEnrollmentRequest& request, + const FinishEnrollmentCallback& callback, + const ErrorCallback& error_callback)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockCryptAuthClient); +}; + +class MockCryptAuthClientFactory : public CryptAuthClientFactory { + public: + class Observer { + public: + // Called with the new instance when it is requested from the factory, + // allowing expectations to be set. Ownership of |client| will be taken by + // the caller of CreateInstance(). + virtual void OnCryptAuthClientCreated(MockCryptAuthClient* client) = 0; + }; + + // If |is_strict| is true, then StrictMocks will be created. Otherwise, + // NiceMocks will be created. + explicit MockCryptAuthClientFactory(bool is_strict); + ~MockCryptAuthClientFactory() override; + + // CryptAuthClientFactory: + scoped_ptr<CryptAuthClient> CreateInstance() override; + + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + + private: + // Whether to create StrictMocks or NiceMocks. + bool is_strict_; + + // Observers of the factory. + ObserverList<Observer> observer_list_; + + DISALLOW_COPY_AND_ASSIGN(MockCryptAuthClientFactory); +}; + +} // namespace proximity_auth + +#endif // COMPONENTS_PROXIMITY_AUTH_MOCK_CRYPTAUTH_CLIENT_H
diff --git a/components/signin/core/browser/account_tracker_service.cc b/components/signin/core/browser/account_tracker_service.cc index 2da5a986..1191a96 100644 --- a/components/signin/core/browser/account_tracker_service.cc +++ b/components/signin/core/browser/account_tracker_service.cc
@@ -28,6 +28,9 @@ const char kAccountEmailPath[] = "email"; const char kAccountGaiaPath[] = "gaia"; const char kAccountHostedDomainPath[] = "hd"; +const char kAccountFullNamePath[] = "full_name"; +const char kAccountGivenNamePath[] = "given_name"; +const char kAccountLocalePath[] = "locale"; #if !defined(OS_ANDROID) && !defined(OS_IOS) // IsRefreshTokenDeviceIdExperimentEnabled is called from @@ -167,8 +170,9 @@ AccountTrackerService::AccountInfo::~AccountInfo() {} bool AccountTrackerService::AccountInfo::IsValid() { - return account_id.empty() || email.empty() || gaia.empty() || - hosted_domain.empty(); + return !account_id.empty() && !email.empty() && !gaia.empty() && + !hosted_domain.empty() && !full_name.empty() && !given_name.empty() && + !locale.empty(); } @@ -319,7 +323,7 @@ // ensure the Fetch doesn't occur until after ProfileImpl::OnPrefsLoaded(). if (state.info.gaia.empty()) #else - if (state.info.IsValid()) + if (!state.info.IsValid()) #endif StartFetchingUserInfo(account_id); @@ -420,6 +424,10 @@ state.info.hosted_domain = kNoHostedDomainFound; } + user_info->GetString("name", &state.info.full_name); + user_info->GetString("given_name", &state.info.given_name); + user_info->GetString("locale", &state.info.locale); + NotifyAccountUpdated(state); SaveToPrefs(state); } @@ -470,7 +478,13 @@ state.info.email = base::UTF16ToUTF8(value); if (dict->GetString(kAccountHostedDomainPath, &value)) state.info.hosted_domain = base::UTF16ToUTF8(value); - if (!state.info.IsValid()) + if (dict->GetString(kAccountFullNamePath, &value)) + state.info.full_name = base::UTF16ToUTF8(value); + if (dict->GetString(kAccountGivenNamePath, &value)) + state.info.given_name = base::UTF16ToUTF8(value); + if (dict->GetString(kAccountLocalePath, &value)) + state.info.locale = base::UTF16ToUTF8(value); + if (state.info.IsValid()) NotifyAccountUpdated(state); } } @@ -501,6 +515,9 @@ dict->SetString(kAccountEmailPath, state.info.email); dict->SetString(kAccountGaiaPath, state.info.gaia); dict->SetString(kAccountHostedDomainPath, state.info.hosted_domain); + dict->SetString(kAccountFullNamePath, state.info.full_name); + dict->SetString(kAccountGivenNamePath, state.info.given_name); + dict->SetString(kAccountLocalePath, state.info.locale); } 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 d037eb2..20249dd 100644 --- a/components/signin/core/browser/account_tracker_service.h +++ b/components/signin/core/browser/account_tracker_service.h
@@ -49,7 +49,10 @@ std::string account_id; // The account ID used by OAuth2TokenService. std::string gaia; std::string email; + std::string full_name; + std::string given_name; std::string hosted_domain; + std::string locale; // TODO(rogerta): eventually this structure will include other information // about the account, like full name, profile picture URL, etc.
diff --git a/components/signin/core/browser/account_tracker_service_unittest.cc b/components/signin/core/browser/account_tracker_service_unittest.cc index c5bb7b4..137e8e31 100644 --- a/components/signin/core/browser/account_tracker_service_unittest.cc +++ b/components/signin/core/browser/account_tracker_service_unittest.cc
@@ -22,6 +22,23 @@ namespace { +const std::string kTokenInfoResponseFormat = + "{ \ + \"id\": \"%s\", \ + \"email\": \"%s\", \ + \"hd\": \"\", \ + \"name\": \"%s\", \ + \"given_name\": \"%s\", \ + \"locale\": \"%s\" \ + }"; + +const std::string kTokenInfoIncompleteResponseFormat = + "{ \ + \"id\": \"%s\", \ + \"email\": \"%s\", \ + \"hd\": \"\", \ + }"; + enum TrackingEventType { UPDATED, REMOVED, @@ -35,6 +52,30 @@ return "gaia-" + account_id; } +std::string AccountIdToFullName(const std::string account_id) { + return "full-name-" + account_id; +} + +std::string AccountIdToGivenName(const std::string account_id) { + return "given-name-" + account_id; +} + +std::string AccountIdToLocale(const std::string account_id) { + return "locale-" + account_id; +} + +void CheckAccountDetails(const std::string account_id, + const AccountTrackerService::AccountInfo& info) { + EXPECT_EQ(account_id, info.account_id); + EXPECT_EQ(AccountIdToGaiaId(account_id), info.gaia); + EXPECT_EQ(AccountIdToEmail(account_id), info.email); + EXPECT_EQ(AccountTrackerService::kNoHostedDomainFound, + info.hosted_domain); + EXPECT_EQ(AccountIdToFullName(account_id), info.full_name); + EXPECT_EQ(AccountIdToGivenName(account_id), info.given_name); + EXPECT_EQ(AccountIdToLocale(account_id), info.locale); +} + class TrackingEvent { public: TrackingEvent(TrackingEventType type, @@ -236,11 +277,23 @@ std::string GenerateValidTokenInfoResponse(const std::string& account_id) { return base::StringPrintf( - "{\"id\": \"%s\", \"email\": \"%s\", \"hd\": \"\"}", + kTokenInfoResponseFormat.c_str(), + AccountIdToGaiaId(account_id).c_str(), + AccountIdToEmail(account_id).c_str(), + AccountIdToFullName(account_id).c_str(), + AccountIdToGivenName(account_id).c_str(), + AccountIdToLocale(account_id).c_str()); + } + + std::string GenerateIncompleteTokenInfoResponse( + const std::string& account_id) { + return base::StringPrintf( + kTokenInfoIncompleteResponseFormat.c_str(), AccountIdToGaiaId(account_id).c_str(), AccountIdToEmail(account_id).c_str()); } void ReturnOAuthUrlFetchSuccess(const std::string& account_id); + void ReturnOAuthUrlFetchSuccessIncomplete(const std::string& account_id); void ReturnOAuthUrlFetchFailure(const std::string& account_id); net::TestURLFetcherFactory* test_fetcher_factory() { @@ -287,6 +340,14 @@ GenerateValidTokenInfoResponse(account_id)); } +void AccountTrackerServiceTest::ReturnOAuthUrlFetchSuccessIncomplete( + const std::string& account_id) { + IssueAccessToken(account_id); + ReturnOAuthUrlFetchResults(gaia::GaiaOAuthClient::kUrlFetcherId, + net::HTTP_OK, + GenerateIncompleteTokenInfoResponse(account_id)); +} + void AccountTrackerServiceTest::ReturnOAuthUrlFetchFailure( const std::string& account_id) { IssueAccessToken(account_id); @@ -390,21 +451,9 @@ account_tracker()->GetAccounts(); EXPECT_EQ(3u, infos.size()); - EXPECT_EQ("alpha", infos[0].account_id); - EXPECT_EQ(AccountIdToGaiaId("alpha"), infos[0].gaia); - EXPECT_EQ(AccountIdToEmail("alpha"), infos[0].email); - EXPECT_EQ(AccountTrackerService::kNoHostedDomainFound, - infos[0].hosted_domain); - EXPECT_EQ("beta", infos[1].account_id); - EXPECT_EQ(AccountIdToGaiaId("beta"), infos[1].gaia); - EXPECT_EQ(AccountIdToEmail("beta"), infos[1].email); - EXPECT_EQ(AccountTrackerService::kNoHostedDomainFound, - infos[1].hosted_domain); - EXPECT_EQ("gamma", infos[2].account_id); - EXPECT_EQ(AccountIdToGaiaId("gamma"), infos[2].gaia); - EXPECT_EQ(AccountIdToEmail("gamma"), infos[2].email); - EXPECT_EQ(AccountTrackerService::kNoHostedDomainFound, - infos[2].hosted_domain); + CheckAccountDetails("alpha", infos[0]); + CheckAccountDetails("beta", infos[1]); + CheckAccountDetails("gamma", infos[2]); } TEST_F(AccountTrackerServiceTest, GetAccountInfo_Empty) { @@ -427,10 +476,7 @@ ReturnOAuthUrlFetchSuccess("alpha"); AccountTrackerService::AccountInfo info = account_tracker()->GetAccountInfo("alpha"); - ASSERT_EQ("alpha", info.account_id); - ASSERT_EQ(AccountIdToGaiaId("alpha"), info.gaia); - ASSERT_EQ(AccountIdToEmail("alpha"), info.email); - ASSERT_EQ(AccountTrackerService::kNoHostedDomainFound, info.hosted_domain); + CheckAccountDetails("alpha", info); } TEST_F(AccountTrackerServiceTest, GetAccountInfo_TokenAvailable_EnableNetwork) { @@ -457,10 +503,7 @@ AccountTrackerService::AccountInfo info = tracker.GetAccountInfo("alpha"); - ASSERT_EQ("alpha", info.account_id); - ASSERT_EQ(AccountIdToGaiaId("alpha"), info.gaia); - ASSERT_EQ(AccountIdToEmail("alpha"), info.email); - ASSERT_EQ(AccountTrackerService::kNoHostedDomainFound, info.hosted_domain); + CheckAccountDetails("alpha", info); tracker.Shutdown(); } @@ -516,7 +559,7 @@ tracker.Shutdown(); } - // Create a new tracker and make sure it loads the accounts corectly from + // Create a new tracker and make sure it loads the accounts correctly from // persistence. { AccountTrackerService tracker; @@ -529,11 +572,8 @@ std::vector<AccountTrackerService::AccountInfo> infos = tracker.GetAccounts(); ASSERT_EQ(2u, infos.size()); - EXPECT_EQ(AccountIdToGaiaId("alpha"), infos[0].gaia); - EXPECT_EQ(AccountIdToEmail("alpha"), infos[0].email); - EXPECT_EQ("beta", infos[1].account_id); - EXPECT_EQ(AccountIdToGaiaId("beta"), infos[1].gaia); - EXPECT_EQ(AccountIdToEmail("beta"), infos[1].email); + CheckAccountDetails("alpha", infos[0]); + CheckAccountDetails("beta", infos[1]); // Remove account. SimulateTokenRevoked("alpha"); @@ -551,9 +591,7 @@ std::vector<AccountTrackerService::AccountInfo> infos = tracker.GetAccounts(); ASSERT_EQ(1u, infos.size()); - EXPECT_EQ("beta", infos[0].account_id); - EXPECT_EQ(AccountIdToGaiaId("beta"), infos[0].gaia); - EXPECT_EQ(AccountIdToEmail("beta"), infos[0].email); + CheckAccountDetails("beta", infos[0]); tracker.Shutdown(); } } @@ -575,3 +613,63 @@ EXPECT_EQ(gaia_id, infos[0].gaia); EXPECT_EQ(email, infos[0].email); } + +TEST_F(AccountTrackerServiceTest, UpgradeToFullAccountInfo) { + // Start by simulating an incomplete account info and let it be saved to + // prefs. + { + AccountTrackerService tracker; + tracker.Initialize(token_service(), signin_client()); + tracker.EnableNetworkFetches(); + SimulateTokenAvailable("incomplete"); + ReturnOAuthUrlFetchSuccessIncomplete("incomplete"); + tracker.Shutdown(); + } + + { + AccountTrackerService tracker; + tracker.Initialize(token_service(), signin_client()); + + // Validate that the loaded AccountInfo from prefs is considered invalid. + std::vector<AccountTrackerService::AccountInfo> infos = + tracker.GetAccounts(); + ASSERT_EQ(1u, infos.size()); + ASSERT_FALSE(infos[0].IsValid()); + + // Enable network fetches and simulate the same account getting a refresh + // token containing all the info. + tracker.EnableNetworkFetches(); + SimulateTokenAvailable("incomplete"); + ReturnOAuthUrlFetchSuccess("incomplete"); + + // Validate that the account is now considered valid. + infos = tracker.GetAccounts(); + ASSERT_EQ(1u, infos.size()); + ASSERT_TRUE(infos[0].IsValid()); + + tracker.Shutdown(); + } + + // Reinstantiate a tracker to validate that the AccountInfo saved to prefs is + // now the upgraded one, considered valid. + { + AccountTrackerService tracker; + tracker.AddObserver(observer()); + tracker.Initialize(token_service(), signin_client()); + ASSERT_TRUE(observer()->CheckEvents(TrackingEvent(UPDATED, "incomplete"))); + // Make sure there are no events in the observer + observer()->Clear(); + // Enabling network fetches shouldn't cause any actual fetch since the + // AccountInfos loaded from prefs should be valid. + tracker.EnableNetworkFetches(); + + std::vector<AccountTrackerService::AccountInfo> infos = + tracker.GetAccounts(); + ASSERT_EQ(1u, infos.size()); + ASSERT_TRUE(infos[0].IsValid()); + // Check that no network fetches were made. + ASSERT_TRUE(observer()->CheckEvents()); + + tracker.Shutdown(); + } +}
diff --git a/content/browser/accessibility/snapshot_ax_tree_browsertest.cc b/content/browser/accessibility/snapshot_ax_tree_browsertest.cc new file mode 100644 index 0000000..af82404c --- /dev/null +++ b/content/browser/accessibility/snapshot_ax_tree_browsertest.cc
@@ -0,0 +1,77 @@ +// 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/callback.h" +#include "content/browser/web_contents/web_contents_impl.h" +#include "content/public/test/content_browser_test.h" +#include "content/public/test/content_browser_test_utils.h" +#include "content/public/test/test_utils.h" +#include "content/shell/browser/shell.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/accessibility/ax_node.h" +#include "ui/accessibility/ax_tree.h" + +namespace content { + +namespace { + +class AXTreeSnapshotWaiter { + public: + AXTreeSnapshotWaiter() : loop_runner_(new MessageLoopRunner()) {} + + void Wait() { + loop_runner_->Run(); + } + + const ui::AXTreeUpdate& snapshot() const { return snapshot_; } + + void ReceiveSnapshot(const ui::AXTreeUpdate& snapshot) { + snapshot_ = snapshot; + loop_runner_->Quit(); + } + + private: + ui::AXTreeUpdate snapshot_; + scoped_refptr<MessageLoopRunner> loop_runner_; + + DISALLOW_COPY_AND_ASSIGN(AXTreeSnapshotWaiter); +}; + +} // namespace + +class SnapshotAXTreeBrowserTest : public ContentBrowserTest { + public: + SnapshotAXTreeBrowserTest() {} + ~SnapshotAXTreeBrowserTest() override {} +}; + +IN_PROC_BROWSER_TEST_F(SnapshotAXTreeBrowserTest, + SnapshotAccessibilityTreeFromWebContents) { + GURL url("data:text/html,<button>Click</button>"); + NavigateToURL(shell(), url); + + WebContentsImpl* web_contents = + static_cast<WebContentsImpl*>(shell()->web_contents()); + + AXTreeSnapshotWaiter waiter; + web_contents->RequestAXTreeSnapshot( + base::Bind(&AXTreeSnapshotWaiter::ReceiveSnapshot, + base::Unretained(&waiter))); + waiter.Wait(); + + // Dump the whole tree if one of the assertions below fails + // to aid in debugging why it failed. + SCOPED_TRACE(waiter.snapshot().ToString()); + + ui::AXTree tree(waiter.snapshot()); + ui::AXNode* root = tree.root(); + ASSERT_NE(nullptr, root); + ASSERT_EQ(ui::AX_ROLE_ROOT_WEB_AREA, root->data().role); + ui::AXNode* group = root->ChildAtIndex(0); + ASSERT_EQ(ui::AX_ROLE_GROUP, group->data().role); + ui::AXNode* button = group->ChildAtIndex(0); + ASSERT_EQ(ui::AX_ROLE_BUTTON, button->data().role); +} + +} // namespace content
diff --git a/content/browser/android/content_startup_flags.cc b/content/browser/android/content_startup_flags.cc index e5acab94..e679825 100644 --- a/content/browser/android/content_startup_flags.cc +++ b/content/browser/android/content_startup_flags.cc
@@ -71,12 +71,6 @@ if (base::SysInfo::IsLowEndDevice()) parsed_command_line->AppendSwitch(switches::kInProcessGPU); - // Web Notifications are only supported on Android JellyBean and beyond. - if (base::android::BuildInfo::GetInstance()->sdk_int() < - base::android::SDK_VERSION_JELLY_BEAN) { - parsed_command_line->AppendSwitch(switches::kDisableNotifications); - } - parsed_command_line->AppendSwitch(switches::kEnableViewportMeta); parsed_command_line->AppendSwitch( switches::kMainFrameResizesAreOrientationChanges);
diff --git a/content/browser/browser_thread_impl.cc b/content/browser/browser_thread_impl.cc index a8ce1b0..78e3836 100644 --- a/content/browser/browser_thread_impl.cc +++ b/content/browser/browser_thread_impl.cc
@@ -15,6 +15,7 @@ #include "base/threading/sequenced_worker_pool.h" #include "base/threading/thread_restrictions.h" #include "content/public/browser/browser_thread_delegate.h" +#include "content/public/browser/content_browser_client.h" #include "net/disk_cache/simple/simple_backend_impl.h" #if defined(OS_ANDROID) @@ -365,6 +366,15 @@ } // static +void BrowserThread::PostAfterStartupTask( + const tracked_objects::Location& from_here, + const scoped_refptr<base::TaskRunner>& task_runner, + const base::Closure& task) { + GetContentClient()->browser()->PostAfterStartupTask(from_here, task_runner, + task); +} + +// static base::SequencedWorkerPool* BrowserThread::GetBlockingPool() { return g_globals.Get().blocking_pool.get(); }
diff --git a/content/browser/devtools/browser_devtools_agent_host.cc b/content/browser/devtools/browser_devtools_agent_host.cc new file mode 100644 index 0000000..03fb0e2 --- /dev/null +++ b/content/browser/devtools/browser_devtools_agent_host.cc
@@ -0,0 +1,65 @@ +// 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 "content/browser/devtools/browser_devtools_agent_host.h" + +#include "base/bind.h" +#include "content/browser/devtools/protocol/devtools_protocol_handler.h" +#include "content/browser/devtools/protocol/system_info_handler.h" +#include "content/browser/devtools/protocol/tethering_handler.h" +#include "content/browser/devtools/protocol/tracing_handler.h" + +namespace content { + +scoped_refptr<DevToolsAgentHost> DevToolsAgentHost::CreateForBrowser( + scoped_refptr<base::MessageLoopProxy> tethering_message_loop, + const CreateServerSocketCallback& socket_callback) { + return new BrowserDevToolsAgentHost(tethering_message_loop, socket_callback); +} + +BrowserDevToolsAgentHost::BrowserDevToolsAgentHost( + scoped_refptr<base::MessageLoopProxy> tethering_message_loop, + const CreateServerSocketCallback& socket_callback) + : system_info_handler_(new devtools::system_info::SystemInfoHandler()), + tethering_handler_(new devtools::tethering::TetheringHandler( + socket_callback, tethering_message_loop)), + tracing_handler_(new devtools::tracing::TracingHandler( + devtools::tracing::TracingHandler::Browser)) { + set_handle_all_protocol_commands(); + DevToolsProtocolDispatcher* dispatcher = protocol_handler_->dispatcher(); + dispatcher->SetSystemInfoHandler(system_info_handler_.get()); + dispatcher->SetTetheringHandler(tethering_handler_.get()); + dispatcher->SetTracingHandler(tracing_handler_.get()); +} + +BrowserDevToolsAgentHost::~BrowserDevToolsAgentHost() { +} + +void BrowserDevToolsAgentHost::Attach() { +} + +void BrowserDevToolsAgentHost::Detach() { +} + +DevToolsAgentHost::Type BrowserDevToolsAgentHost::GetType() { + return TYPE_BROWSER; +} + +std::string BrowserDevToolsAgentHost::GetTitle() { + return ""; +} + +GURL BrowserDevToolsAgentHost::GetURL() { + return GURL(); +} + +bool BrowserDevToolsAgentHost::Activate() { + return false; +} + +bool BrowserDevToolsAgentHost::Close() { + return false; +} + +} // content
diff --git a/content/browser/devtools/browser_devtools_agent_host.h b/content/browser/devtools/browser_devtools_agent_host.h new file mode 100644 index 0000000..b4fbb7d --- /dev/null +++ b/content/browser/devtools/browser_devtools_agent_host.h
@@ -0,0 +1,44 @@ +// 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_DEVTOOLS_BROWSER_DEVTOOLS_AGENT_HOST_H_ +#define CONTENT_BROWSER_DEVTOOLS_BROWSER_DEVTOOLS_AGENT_HOST_H_ + +#include "content/browser/devtools/devtools_agent_host_impl.h" + +namespace content { + +namespace devtools { +namespace system_info { class SystemInfoHandler; } +namespace tethering { class TetheringHandler; } +namespace tracing { class TracingHandler; } +} // namespace devtools + +class BrowserDevToolsAgentHost : public DevToolsAgentHostImpl { + private: + friend class DevToolsAgentHost; + BrowserDevToolsAgentHost( + scoped_refptr<base::MessageLoopProxy> tethering_message_loop, + const CreateServerSocketCallback& socket_callback); + ~BrowserDevToolsAgentHost() override; + + // DevToolsAgentHostImpl implementation. + void Attach() override; + void Detach() override; + + // DevToolsAgentHost implementation. + Type GetType() override; + std::string GetTitle() override; + GURL GetURL() override; + bool Activate() override; + bool Close() override; + + scoped_ptr<devtools::system_info::SystemInfoHandler> system_info_handler_; + scoped_ptr<devtools::tethering::TetheringHandler> tethering_handler_; + scoped_ptr<devtools::tracing::TracingHandler> tracing_handler_; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_DEVTOOLS_BROWSER_DEVTOOLS_AGENT_HOST_H_
diff --git a/content/browser/devtools/devtools_agent_host_impl.cc b/content/browser/devtools/devtools_agent_host_impl.cc index efd76cb..3eb6acec 100644 --- a/content/browser/devtools/devtools_agent_host_impl.cc +++ b/content/browser/devtools/devtools_agent_host_impl.cc
@@ -35,6 +35,16 @@ } // namespace // static +std::string DevToolsAgentHost::GetProtocolVersion() { + return std::string(devtools::kProtocolVersion); +} + +// static +bool DevToolsAgentHost::IsSupportedProtocolVersion(const std::string& version) { + return devtools::IsSupportedProtocolVersion(version); +} + +// static DevToolsAgentHost::List DevToolsAgentHost::GetOrCreateAll() { List result; SharedWorkerDevToolsAgentHost::List shared_list; @@ -71,7 +81,8 @@ base::Bind(&DevToolsAgentHostImpl::SendMessageToClient, base::Unretained(this)))), id_(base::GenerateGUID()), - client_(NULL) { + client_(NULL), + handle_all_commands_(false) { DCHECK_CURRENTLY_ON(BrowserThread::UI); g_instances.Get()[id_] = this; } @@ -144,10 +155,6 @@ void DevToolsAgentHostImpl::ConnectWebContents(WebContents* wc) { } -bool DevToolsAgentHostImpl::IsWorker() const { - return false; -} - void DevToolsAgentHostImpl::HostClosed() { if (!client_) return; @@ -244,7 +251,10 @@ } } - return protocol_handler_->HandleOptionalCommand(command.Pass()); + if (!handle_all_commands_) + return protocol_handler_->HandleOptionalCommand(command.Pass()); + protocol_handler_->HandleCommand(command.Pass()); + return true; } } // namespace content
diff --git a/content/browser/devtools/devtools_agent_host_impl.h b/content/browser/devtools/devtools_agent_host_impl.h index 07112c3..698bfe90 100644 --- a/content/browser/devtools/devtools_agent_host_impl.h +++ b/content/browser/devtools/devtools_agent_host_impl.h
@@ -45,7 +45,6 @@ WebContents* GetWebContents() override; void DisconnectWebContents() override; void ConnectWebContents(WebContents* wc) override; - bool IsWorker() const override; protected: DevToolsAgentHostImpl(); @@ -53,6 +52,7 @@ scoped_ptr<DevToolsProtocolHandler> protocol_handler_; + void set_handle_all_protocol_commands() { handle_all_commands_ = true; } void HostClosed(); void SendMessageToClient(const std::string& message); static void NotifyCallbacks(DevToolsAgentHostImpl* agent_host, bool attached); @@ -62,6 +62,7 @@ const std::string id_; DevToolsAgentHostClient* client_; + bool handle_all_commands_; }; } // namespace content
diff --git a/content/browser/devtools/devtools_http_handler_impl.cc b/content/browser/devtools/devtools_http_handler_impl.cc index fb25825d..4cae4481 100644 --- a/content/browser/devtools/devtools_http_handler_impl.cc +++ b/content/browser/devtools/devtools_http_handler_impl.cc
@@ -13,14 +13,11 @@ #include "base/message_loop/message_loop_proxy.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" #include "base/threading/thread.h" #include "base/values.h" #include "content/browser/devtools/devtools_manager.h" -#include "content/browser/devtools/protocol/devtools_protocol_handler.h" -#include "content/browser/devtools/protocol/system_info_handler.h" -#include "content/browser/devtools/protocol/tethering_handler.h" -#include "content/browser/devtools/protocol/tracing_handler.h" -#include "content/common/devtools_messages.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/devtools_http_handler.h" @@ -71,7 +68,6 @@ // added back pressure on the TraceComplete message protocol - crbug.com/456845. const int32 kSendBufferSizeForDevTools = 256 * 1024 * 1024; // 256Mb -class BrowserTarget; class DevToolsAgentHostClientImpl; class ServerWrapper; @@ -148,8 +144,6 @@ ServerSocketFactory* socket_factory_; typedef std::map<std::string, DevToolsTarget*> TargetMap; TargetMap target_map_; - typedef std::map<int, BrowserTarget*> BrowserTargets; - BrowserTargets browser_targets_; base::WeakPtrFactory<DevToolsHttpHandlerImpl> weak_factory_; DISALLOW_COPY_AND_ASSIGN(DevToolsHttpHandlerImpl); @@ -346,7 +340,7 @@ DevToolsAgentHostClientImpl(base::MessageLoop* message_loop, ServerWrapper* server_wrapper, int connection_id, - DevToolsAgentHost* agent_host) + scoped_refptr<DevToolsAgentHost> agent_host) : message_loop_(message_loop), server_wrapper_(server_wrapper), connection_id_(connection_id), @@ -363,13 +357,12 @@ bool replaced_with_another_client) override { DCHECK(agent_host == agent_host_.get()); - base::Callback<void(const std::string&)> raw_message_callback( - base::Bind(&DevToolsAgentHostClientImpl::DispatchProtocolMessage, - base::Unretained(this), base::Unretained(agent_host))); - devtools::inspector::Client inspector(raw_message_callback); - inspector.Detached(devtools::inspector::DetachedParams::Create() - ->set_reason(replaced_with_another_client ? - "replaced_with_devtools" : "target_closed")); + std::string message = base::StringPrintf( + "{ \"method\": \"Inspector.detached\", " + "\"params\": { \"reason\": \"%s\"} }", + replaced_with_another_client ? + "replaced_with_devtools" : "target_closed"); + DispatchProtocolMessage(agent_host, message); agent_host_ = nullptr; message_loop_->PostTask( @@ -407,59 +400,6 @@ return target1->GetLastActivityTime() > target2->GetLastActivityTime(); } -// BrowserTarget ------------------------------------------------------------- - -class BrowserTarget { - public: - BrowserTarget(base::MessageLoop* message_loop, - ServerWrapper* server_wrapper, - DevToolsHttpHandler::ServerSocketFactory* socket_factory, - int connection_id) - : message_loop_(message_loop), - server_wrapper_(server_wrapper), - connection_id_(connection_id), - system_info_handler_(new devtools::system_info::SystemInfoHandler()), - tethering_handler_(new devtools::tethering::TetheringHandler( - socket_factory, message_loop->message_loop_proxy())), - tracing_handler_(new devtools::tracing::TracingHandler( - devtools::tracing::TracingHandler::Browser)), - protocol_handler_(new DevToolsProtocolHandler( - base::Bind(&BrowserTarget::Respond, base::Unretained(this)))) { - DevToolsProtocolDispatcher* dispatcher = protocol_handler_->dispatcher(); - dispatcher->SetSystemInfoHandler(system_info_handler_.get()); - dispatcher->SetTetheringHandler(tethering_handler_.get()); - dispatcher->SetTracingHandler(tracing_handler_.get()); - } - - void HandleMessage(const std::string& message) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - std::string error_response; - scoped_ptr<base::DictionaryValue> command = - protocol_handler_->ParseCommand(message); - if (command) - protocol_handler_->HandleCommand(command.Pass()); - } - - void Respond(const std::string& message) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - message_loop_->PostTask( - FROM_HERE, - base::Bind(&ServerWrapper::SendOverWebSocket, - base::Unretained(server_wrapper_), - connection_id_, - message)); - } - - private: - base::MessageLoop* const message_loop_; - ServerWrapper* const server_wrapper_; - const int connection_id_; - scoped_ptr<devtools::system_info::SystemInfoHandler> system_info_handler_; - scoped_ptr<devtools::tethering::TetheringHandler> tethering_handler_; - scoped_ptr<devtools::tracing::TracingHandler> tracing_handler_; - scoped_ptr<DevToolsProtocolHandler> protocol_handler_; -}; - } // namespace // DevToolsHttpHandler ------------------------------------------------------- @@ -467,7 +407,7 @@ // static bool DevToolsHttpHandler::IsSupportedProtocolVersion( const std::string& version) { - return devtools::IsSupportedProtocolVersion(version); + return DevToolsAgentHost::IsSupportedProtocolVersion(version); } // static @@ -511,7 +451,6 @@ DevToolsHttpHandlerImpl::~DevToolsHttpHandlerImpl() { TerminateOnUI(thread_, server_wrapper_, socket_factory_); STLDeleteValues(&target_map_); - STLDeleteValues(&browser_targets_); STLDeleteValues(&connection_to_client_); } @@ -718,7 +657,8 @@ if (command == "version") { base::DictionaryValue version; - version.SetString("Protocol-Version", devtools::kProtocolVersion); + version.SetString("Protocol-Version", + DevToolsAgentHost::GetProtocolVersion().c_str()); version.SetString("WebKit-Version", GetWebKitVersion()); version.SetString("Browser", GetContentClient()->GetProduct()); version.SetString("User-Agent", GetContentClient()->GetUserAgent()); @@ -880,10 +820,13 @@ std::string browser_prefix = "/devtools/browser"; size_t browser_pos = request.path.find(browser_prefix); if (browser_pos == 0) { - browser_targets_[connection_id] = new BrowserTarget(thread_->message_loop(), - server_wrapper_, - socket_factory_, - connection_id); + scoped_refptr<DevToolsAgentHost> browser_agent = + DevToolsAgentHost::CreateForBrowser( + thread_->message_loop_proxy(), + base::Bind(&ServerSocketFactory::CreateForTethering, + base::Unretained(socket_factory_))); + connection_to_client_[connection_id] = new DevToolsAgentHostClientImpl( + thread_->message_loop(), server_wrapper_, connection_id, browser_agent); AcceptWebSocket(connection_id, request); return; } @@ -910,7 +853,7 @@ } DevToolsAgentHostClientImpl* client_host = new DevToolsAgentHostClientImpl( - thread_->message_loop(), server_wrapper_, connection_id, agent.get()); + thread_->message_loop(), server_wrapper_, connection_id, agent); connection_to_client_[connection_id] = client_host; AcceptWebSocket(connection_id, request); @@ -919,12 +862,6 @@ void DevToolsHttpHandlerImpl::OnWebSocketMessage( int connection_id, const std::string& data) { - BrowserTargets::iterator browser_it = browser_targets_.find(connection_id); - if (browser_it != browser_targets_.end()) { - browser_it->second->HandleMessage(data); - return; - } - ConnectionToClientMap::iterator it = connection_to_client_.find(connection_id); if (it != connection_to_client_.end()) @@ -932,13 +869,6 @@ } void DevToolsHttpHandlerImpl::OnClose(int connection_id) { - BrowserTargets::iterator browser_it = browser_targets_.find(connection_id); - if (browser_it != browser_targets_.end()) { - delete browser_it->second; - browser_targets_.erase(connection_id); - return; - } - ConnectionToClientMap::iterator it = connection_to_client_.find(connection_id); if (it != connection_to_client_.end()) {
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc index 129b125b..55e9826 100644 --- a/content/browser/devtools/protocol/network_handler.cc +++ b/content/browser/devtools/protocol/network_handler.cc
@@ -4,26 +4,196 @@ #include "content/browser/devtools/protocol/network_handler.h" +#include "base/containers/hash_tables.h" +#include "base/strings/stringprintf.h" +#include "content/browser/frame_host/frame_tree_node.h" +#include "content/browser/frame_host/render_frame_host_impl.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/content_browser_client.h" +#include "content/public/browser/resource_context.h" +#include "content/public/browser/site_instance.h" #include "content/public/common/content_client.h" +#include "net/cookies/cookie_store.h" +#include "net/url_request/url_request_context.h" +#include "net/url_request/url_request_context_getter.h" namespace content { namespace devtools { namespace network { +using CookieListCallback = net::CookieStore::GetCookieListCallback; + +namespace { + +net::URLRequestContext* GetRequestContextOnIO( + ResourceContext* resource_context, + net::URLRequestContextGetter* context_getter, + const GURL& url) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + net::URLRequestContext* context = + GetContentClient()->browser()->OverrideRequestContextForURL( + url, resource_context); + if (!context) + context = context_getter->GetURLRequestContext(); + return context; +} + +void GotCookiesForURLOnIO( + const CookieListCallback& callback, + const net::CookieList& cookie_list) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind(callback, cookie_list)); +} + +void GetCookiesForURLOnIO( + ResourceContext* resource_context, + net::URLRequestContextGetter* context_getter, + const GURL& url, + const CookieListCallback& callback) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + net::URLRequestContext* request_context = + GetRequestContextOnIO(resource_context, context_getter, url); + request_context->cookie_store()->GetAllCookiesForURLAsync( + url, base::Bind(&GotCookiesForURLOnIO, callback)); +} + +void GetCookiesForURLOnUI( + ResourceContext* resource_context, + net::URLRequestContextGetter* context_getter, + const GURL& url, + const CookieListCallback& callback) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(&GetCookiesForURLOnIO, + base::Unretained(resource_context), + base::Unretained(context_getter), + url, + callback)); +} + +void DeletedCookieOnIO(const base::Closure& callback) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + callback); +} + +void DeleteCookieOnIO( + ResourceContext* resource_context, + net::URLRequestContextGetter* context_getter, + const GURL& url, + const std::string& cookie_name, + const base::Closure& callback) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + net::URLRequestContext* request_context = + GetRequestContextOnIO(resource_context, context_getter, url); + request_context->cookie_store()->DeleteCookieAsync( + url, cookie_name, base::Bind(&DeletedCookieOnIO, callback)); +} + +void DeleteCookieOnUI( + ResourceContext* resource_context, + net::URLRequestContextGetter* context_getter, + const GURL& url, + const std::string& cookie_name, + const base::Closure& callback) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(&DeleteCookieOnIO, + base::Unretained(resource_context), + base::Unretained(context_getter), + url, + cookie_name, + callback)); +} + +class GetCookiesCommand { + public: + explicit GetCookiesCommand( + RenderFrameHostImpl* frame_host, + const CookieListCallback& callback) + : callback_(callback), + request_count_(0) { + CookieListCallback got_cookies_callback = base::Bind( + &GetCookiesCommand::GotCookiesForURL, base::Unretained(this)); + BrowserContext* browser_context = + frame_host->GetSiteInstance()->GetBrowserContext(); + + std::queue<FrameTreeNode*> queue; + queue.push(frame_host->frame_tree_node()); + while (!queue.empty()) { + FrameTreeNode* node = queue.front(); + queue.pop(); + + // Only traverse nodes with the same local root. + if (node->current_frame_host()->IsCrossProcessSubframe()) + continue; + int process_id = node->current_frame_host()->GetProcess()->GetID(); + ++request_count_; + GetCookiesForURLOnUI( + browser_context->GetResourceContext(), + browser_context->GetRequestContextForRenderProcess(process_id), + node->current_url(), + got_cookies_callback); + + for (size_t i = 0; i < node->child_count(); ++i) + queue.push(node->child_at(i)); + } + } + + private: + void GotCookiesForURL(const net::CookieList& cookie_list) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + for (const net::CanonicalCookie& cookie : cookie_list) { + std::string key = base::StringPrintf( + "%s::%s::%s::%d", + cookie.Name().c_str(), + cookie.Domain().c_str(), + cookie.Path().c_str(), + cookie.IsSecure()); + cookies_[key] = cookie; + } + --request_count_; + if (!request_count_) { + net::CookieList list; + list.reserve(cookies_.size()); + for (const auto& pair : cookies_) + list.push_back(pair.second); + callback_.Run(list); + delete this; + } + } + + CookieListCallback callback_; + int request_count_; + base::hash_map<std::string, net::CanonicalCookie> cookies_; +}; + +} // namespace + typedef DevToolsProtocolClient::Response Response; -NetworkHandler::NetworkHandler() : host_(nullptr) { +NetworkHandler::NetworkHandler() : host_(nullptr), weak_factory_(this) { } NetworkHandler::~NetworkHandler() { } -void NetworkHandler::SetRenderFrameHost(RenderFrameHost* host) { +void NetworkHandler::SetRenderFrameHost(RenderFrameHostImpl* host) { host_ = host; } -void NetworkHandler::SetClient(scoped_ptr<DevToolsProtocolClient> client) { +void NetworkHandler::SetClient(scoped_ptr<Client> client) { + client_.swap(client); } Response NetworkHandler::ClearBrowserCache() { @@ -39,15 +209,63 @@ } Response NetworkHandler::GetCookies(DevToolsCommandId command_id) { + if (!host_) + return Response::InternalError("Could not connect to view"); + new GetCookiesCommand( + host_, + base::Bind(&NetworkHandler::SendGetCookiesResponse, + weak_factory_.GetWeakPtr(), + command_id)); return Response::OK(); } -Response NetworkHandler::DeleteCookie(DevToolsCommandId command_id, - const std::string& cookie_name, - const std::string& url) { +void NetworkHandler::SendGetCookiesResponse( + DevToolsCommandId command_id, + const net::CookieList& cookie_list) { + std::vector<scoped_refptr<Cookie>> cookies; + for (size_t i = 0; i < cookie_list.size(); ++i) { + const net::CanonicalCookie& cookie = cookie_list[i]; + cookies.push_back(Cookie::Create() + ->set_name(cookie.Name()) + ->set_value(cookie.Value()) + ->set_domain(cookie.Domain()) + ->set_path(cookie.Path()) + ->set_expires(cookie.ExpiryDate().ToDoubleT() * 1000) + ->set_size(cookie.Name().length() + cookie.Value().length()) + ->set_http_only(cookie.IsHttpOnly()) + ->set_secure(cookie.IsSecure()) + ->set_session(!cookie.IsPersistent())); + } + client_->SendGetCookiesResponse(command_id, + GetCookiesResponse::Create()->set_cookies(cookies)); +} + +Response NetworkHandler::DeleteCookie( + DevToolsCommandId command_id, + const std::string& cookie_name, + const std::string& url) { + if (!host_) + return Response::InternalError("Could not connect to view"); + BrowserContext* browser_context = + host_->GetSiteInstance()->GetBrowserContext(); + int process_id = host_->GetProcess()->GetID(); + DeleteCookieOnUI( + browser_context->GetResourceContext(), + browser_context->GetRequestContextForRenderProcess(process_id), + GURL(url), + cookie_name, + base::Bind(&NetworkHandler::SendDeleteCookieResponse, + weak_factory_.GetWeakPtr(), + command_id)); return Response::OK(); } +void NetworkHandler::SendDeleteCookieResponse(DevToolsCommandId command_id) { + client_->SendDeleteCookieResponse(command_id, + DeleteCookieResponse::Create()); +} + + Response NetworkHandler::CanEmulateNetworkConditions(bool* result) { *result = false; return Response::OK();
diff --git a/content/browser/devtools/protocol/network_handler.h b/content/browser/devtools/protocol/network_handler.h index b9a8a9d6..b54a0cb 100644 --- a/content/browser/devtools/protocol/network_handler.h +++ b/content/browser/devtools/protocol/network_handler.h
@@ -5,11 +5,13 @@ #ifndef CONTENT_BROWSER_DEVTOOLS_PROTOCOL_NETWORK_HANDLER_H_ #define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_NETWORK_HANDLER_H_ +#include "base/memory/weak_ptr.h" #include "content/browser/devtools/protocol/devtools_protocol_handler.h" +#include "net/cookies/canonical_cookie.h" namespace content { -class RenderFrameHost; +class RenderFrameHostImpl; namespace devtools { namespace network { @@ -21,8 +23,8 @@ NetworkHandler(); virtual ~NetworkHandler(); - void SetRenderFrameHost(RenderFrameHost* host); - void SetClient(scoped_ptr<DevToolsProtocolClient> client); + void SetRenderFrameHost(RenderFrameHostImpl* host); + void SetClient(scoped_ptr<Client> client); Response ClearBrowserCache(); Response ClearBrowserCookies(); @@ -38,7 +40,14 @@ double upload_throughput); private: - RenderFrameHost* host_; + void SendGetCookiesResponse( + DevToolsCommandId command_id, + const net::CookieList& cookie_list); + void SendDeleteCookieResponse(DevToolsCommandId command_id); + + RenderFrameHostImpl* host_; + scoped_ptr<Client> client_; + base::WeakPtrFactory<NetworkHandler> weak_factory_; DISALLOW_COPY_AND_ASSIGN(NetworkHandler); };
diff --git a/content/browser/devtools/protocol/tethering_handler.cc b/content/browser/devtools/protocol/tethering_handler.cc index efdf0d14..291a132 100644 --- a/content/browser/devtools/protocol/tethering_handler.cc +++ b/content/browser/devtools/protocol/tethering_handler.cc
@@ -27,6 +27,8 @@ const int kMaxTetheringPort = 32767; using Response = DevToolsProtocolClient::Response; +using CreateServerSocketCallback = + base::Callback<scoped_ptr<net::ServerSocket>(std::string*)>; class SocketPump { public: @@ -36,9 +38,9 @@ pending_destruction_(false) { } - std::string Init(DevToolsHttpHandler::ServerSocketFactory* socket_factory) { + std::string Init(const CreateServerSocketCallback& socket_callback) { std::string channel_name; - server_socket_ = socket_factory->CreateForTethering(&channel_name); + server_socket_ = socket_callback.Run(&channel_name); if (!server_socket_.get() || channel_name.empty()) SelfDestruct(); @@ -157,9 +159,9 @@ typedef base::Callback<void(uint16, const std::string&)> AcceptedCallback; BoundSocket(AcceptedCallback accepted_callback, - DevToolsHttpHandler::ServerSocketFactory* socket_factory) + const CreateServerSocketCallback& socket_callback) : accepted_callback_(accepted_callback), - socket_factory_(socket_factory), + socket_callback_(socket_callback), socket_(new net::TCPServerSocket(NULL, net::NetLog::Source())), port_(0) { } @@ -213,13 +215,13 @@ return; SocketPump* pump = new SocketPump(accept_socket_.release()); - std::string name = pump->Init(socket_factory_); + std::string name = pump->Init(socket_callback_); if (!name.empty()) accepted_callback_.Run(port_, name); } AcceptedCallback accepted_callback_; - DevToolsHttpHandler::ServerSocketFactory* socket_factory_; + CreateServerSocketCallback socket_callback_; scoped_ptr<net::ServerSocket> socket_; scoped_ptr<net::StreamSocket> accept_socket_; uint16 port_; @@ -233,7 +235,7 @@ public: TetheringImpl( base::WeakPtr<TetheringHandler> handler, - DevToolsHttpHandler::ServerSocketFactory* socket_factory); + const CreateServerSocketCallback& socket_callback); ~TetheringImpl(); void Bind(DevToolsCommandId command_id, uint16 port); @@ -245,7 +247,7 @@ const std::string& message); base::WeakPtr<TetheringHandler> handler_; - DevToolsHttpHandler::ServerSocketFactory* socket_factory_; + CreateServerSocketCallback socket_callback_; typedef std::map<uint16, BoundSocket*> BoundSockets; BoundSockets bound_sockets_; @@ -253,9 +255,9 @@ TetheringHandler::TetheringImpl::TetheringImpl( base::WeakPtr<TetheringHandler> handler, - DevToolsHttpHandler::ServerSocketFactory* socket_factory) + const CreateServerSocketCallback& socket_callback) : handler_(handler), - socket_factory_(socket_factory) { + socket_callback_(socket_callback) { } TetheringHandler::TetheringImpl::~TetheringImpl() { @@ -272,7 +274,7 @@ BoundSocket::AcceptedCallback callback = base::Bind( &TetheringHandler::TetheringImpl::Accepted, base::Unretained(this)); scoped_ptr<BoundSocket> bound_socket( - new BoundSocket(callback, socket_factory_)); + new BoundSocket(callback, socket_callback_)); if (!bound_socket->Listen(port)) { SendInternalError(command_id, "Could not bind port"); return; @@ -327,9 +329,9 @@ TetheringHandler::TetheringImpl* TetheringHandler::impl_ = nullptr; TetheringHandler::TetheringHandler( - DevToolsHttpHandler::ServerSocketFactory* socket_factory, + const CreateServerSocketCallback& socket_callback, scoped_refptr<base::MessageLoopProxy> message_loop_proxy) - : socket_factory_(socket_factory), + : socket_callback_(socket_callback), message_loop_proxy_(message_loop_proxy), is_active_(false), weak_factory_(this) { @@ -357,7 +359,7 @@ if (impl_) return false; is_active_ = true; - impl_ = new TetheringImpl(weak_factory_.GetWeakPtr(), socket_factory_); + impl_ = new TetheringImpl(weak_factory_.GetWeakPtr(), socket_callback_); return true; }
diff --git a/content/browser/devtools/protocol/tethering_handler.h b/content/browser/devtools/protocol/tethering_handler.h index ac6afc8..6be8a0a 100644 --- a/content/browser/devtools/protocol/tethering_handler.h +++ b/content/browser/devtools/protocol/tethering_handler.h
@@ -18,8 +18,10 @@ class TetheringHandler { public: using Response = DevToolsProtocolClient::Response; + using CreateServerSocketCallback = + base::Callback<scoped_ptr<net::ServerSocket>(std::string*)>; - TetheringHandler(DevToolsHttpHandler::ServerSocketFactory* delegate, + TetheringHandler(const CreateServerSocketCallback& socket_callback, scoped_refptr<base::MessageLoopProxy> message_loop_proxy); ~TetheringHandler(); @@ -40,7 +42,7 @@ const std::string& message); scoped_ptr<Client> client_; - DevToolsHttpHandler::ServerSocketFactory* socket_factory_; + CreateServerSocketCallback socket_callback_; scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; bool is_active_; base::WeakPtrFactory<TetheringHandler> weak_factory_;
diff --git a/content/browser/devtools/worker_devtools_agent_host.cc b/content/browser/devtools/worker_devtools_agent_host.cc index 204435a..fcf8dd7 100644 --- a/content/browser/devtools/worker_devtools_agent_host.cc +++ b/content/browser/devtools/worker_devtools_agent_host.cc
@@ -11,10 +11,6 @@ namespace content { -bool WorkerDevToolsAgentHost::IsWorker() const { - return true; -} - BrowserContext* WorkerDevToolsAgentHost::GetBrowserContext() { RenderProcessHost* rph = RenderProcessHost::FromID(worker_id_.first); return rph ? rph->GetBrowserContext() : nullptr;
diff --git a/content/browser/devtools/worker_devtools_agent_host.h b/content/browser/devtools/worker_devtools_agent_host.h index ae5e39fc0..7bd5128 100644 --- a/content/browser/devtools/worker_devtools_agent_host.h +++ b/content/browser/devtools/worker_devtools_agent_host.h
@@ -19,7 +19,6 @@ typedef std::pair<int, int> WorkerId; // DevToolsAgentHost override. - bool IsWorker() const override; BrowserContext* GetBrowserContext() override; // IPCDevToolsAgentHost implementation.
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index d4cc6f5..6d89910 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -64,6 +64,7 @@ #include "content/public/common/url_constants.h" #include "content/public/common/url_utils.h" #include "ui/accessibility/ax_tree.h" +#include "ui/accessibility/ax_tree_update.h" #include "url/gurl.h" #if defined(OS_MACOSX) @@ -381,6 +382,8 @@ OnAccessibilityLocationChanges) IPC_MESSAGE_HANDLER(AccessibilityHostMsg_FindInPageResult, OnAccessibilityFindInPageResult) + IPC_MESSAGE_HANDLER(AccessibilityHostMsg_SnapshotResponse, + OnAccessibilitySnapshotResponse) IPC_MESSAGE_HANDLER(FrameHostMsg_ToggleFullscreen, OnToggleFullscreen) // The following message is synthetic and doesn't come from RenderFrame, but // from RenderProcessHost. @@ -1069,6 +1072,12 @@ SetRenderFrameCreated(false); InvalidateMojoConnection(); + // Execute any pending AX tree snapshot callbacks with an empty response, + // since we're never going to get a response from this renderer. + for (const auto& iter : ax_tree_snapshot_callbacks_) + iter.second.Run(ui::AXTreeUpdate()); + ax_tree_snapshot_callbacks_.clear(); + if (frame_tree_node_->IsMainFrame()) { // RenderViewHost/RenderWidgetHost needs to reset some stuff. render_view_host_->RendererExited( @@ -1078,6 +1087,10 @@ render_view_host_, static_cast<base::TerminationStatus>(status), exit_code); } + + // Note: don't add any more code at this point in the function because + // |this| may be deleted. Any additional cleanup should happen before + // the last block of code here. } void RenderFrameHostImpl::OnSwappedOut() { @@ -1392,6 +1405,18 @@ } } +void RenderFrameHostImpl::OnAccessibilitySnapshotResponse( + int callback_id, + const ui::AXTreeUpdate& snapshot) { + const auto& it = ax_tree_snapshot_callbacks_.find(callback_id); + if (it != ax_tree_snapshot_callbacks_.end()) { + it->second.Run(snapshot); + ax_tree_snapshot_callbacks_.erase(it); + } else { + NOTREACHED() << "Received AX tree snapshot response for unknown id"; + } +} + void RenderFrameHostImpl::OnToggleFullscreen(bool enter_fullscreen) { if (enter_fullscreen) delegate_->EnterFullscreenMode(GetLastCommittedURL().GetOrigin()); @@ -1805,6 +1830,14 @@ Send(new FrameMsg_SetAccessibilityMode(routing_id_, mode)); } +void RenderFrameHostImpl::RequestAXTreeSnapshot( + AXTreeSnapshotCallback callback) { + static int next_id = 1; + int callback_id = next_id++; + Send(new AccessibilityMsg_SnapshotTree(routing_id_, callback_id)); + ax_tree_snapshot_callbacks_.insert(std::make_pair(callback_id, callback)); +} + void RenderFrameHostImpl::SetAccessibilityCallbackForTesting( const base::Callback<void(ui::AXEvent, int)>& callback) { accessibility_testing_callback_ = callback;
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h index 283be24..9ac9b8d 100644 --- a/content/browser/frame_host/render_frame_host_impl.h +++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -91,6 +91,9 @@ : public RenderFrameHost, public BrowserAccessibilityDelegate { public: + typedef base::Callback<void(const ui::AXTreeUpdate&)> + AXTreeSnapshotCallback; + // Keeps track of the state of the RenderFrameHostImpl, particularly with // respect to swap out. enum RenderFrameHostImplState { @@ -366,6 +369,10 @@ // Send a message to the renderer process to change the accessibility mode. void SetAccessibilityMode(AccessibilityMode AccessibilityMode); + // Request a one-time snapshot of the accessibility tree without changing + // the accessibility mode. + void RequestAXTreeSnapshot(AXTreeSnapshotCallback callback); + // Turn on accessibility testing. The given callback will be run // every time an accessibility notification is received from the // renderer process, and the accessibility tree it sent can be @@ -511,6 +518,8 @@ const std::vector<AccessibilityHostMsg_LocationChangeParams>& params); void OnAccessibilityFindInPageResult( const AccessibilityHostMsg_FindInPageResultParams& params); + void OnAccessibilitySnapshotResponse(int callback_id, + const ui::AXTreeUpdate& snapshot); void OnToggleFullscreen(bool enter_fullscreen); #if defined(OS_MACOSX) || defined(OS_ANDROID) @@ -681,6 +690,10 @@ // we don't keep trying to reset forever. int accessibility_reset_count_; + // The mapping from callback id to corresponding callback for pending + // accessibility tree snapshot calls created by RequestAXTreeSnapshot. + std::map<int, AXTreeSnapshotCallback> ax_tree_snapshot_callbacks_; + // Callback when an event is received, for testing. base::Callback<void(ui::AXEvent, int)> accessibility_testing_callback_; // The most recently received accessibility tree - for testing only.
diff --git a/content/browser/frame_host/render_frame_host_manager.h b/content/browser/frame_host/render_frame_host_manager.h index 91bf671..0be2701 100644 --- a/content/browser/frame_host/render_frame_host_manager.h +++ b/content/browser/frame_host/render_frame_host_manager.h
@@ -422,14 +422,11 @@ SiteInstance* instance); private: + friend class FrameTreeVisualizer; friend class NavigatorTestWithBrowserSideNavigation; friend class RenderFrameHostManagerTest; - friend class SitePerProcessBrowserTest; friend class TestWebContents; - FRIEND_TEST_ALL_PREFIXES(CrossProcessFrameTreeBrowserTest, - CreateCrossProcessSubframeProxies); - // Stores information regarding a SiteInstance targeted at a specific URL to // allow for comparisons without having to actually create new instances. It // can point to an existing one or store the details needed to create a new
diff --git a/content/browser/frame_host/render_frame_host_manager_browsertest.cc b/content/browser/frame_host/render_frame_host_manager_browsertest.cc index 4de22b0..9de16f8 100644 --- a/content/browser/frame_host/render_frame_host_manager_browsertest.cc +++ b/content/browser/frame_host/render_frame_host_manager_browsertest.cc
@@ -834,6 +834,50 @@ EXPECT_EQ(orig_site_instance, revisit_site_instance); } +// Test that subframes do not crash when sending a postMessage to the top frame +// from an unload handler while the top frame is being swapped out as part of +// navigating cross-process. https://crbug.com/475651. +IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, + PostMessageFromSubframeUnloadHandler) { + StartServer(); + + GURL frame_url(test_server()->GetURL("files/post_message.html")); + GURL main_url("data:text/html,<iframe name='foo' src='" + frame_url.spec() + + "'></iframe>"); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + + // Get the original SiteInstance for later comparison. + scoped_refptr<SiteInstance> orig_site_instance( + shell()->web_contents()->GetSiteInstance()); + EXPECT_NE(nullptr, orig_site_instance.get()); + + // It is safe to obtain the root frame tree node here, as it doesn't change. + FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) + ->GetFrameTree() + ->root(); + ASSERT_EQ(1U, root->child_count()); + EXPECT_EQ(frame_url, root->child_at(0)->current_url()); + + // Register an unload handler that sends a postMessage to the top frame. + EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(), + "registerUnload();")); + + // Navigate the top frame cross-site. This will cause the top frame to be + // swapped out and run unload handlers, and the original renderer process + // should then terminate since it's not rendering any other frames. + RenderProcessHostWatcher exit_observer( + root->current_frame_host()->GetProcess(), + RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION); + EXPECT_TRUE(NavigateToURL(shell(), GetCrossSiteURL("files/title1.html"))); + scoped_refptr<SiteInstance> new_site_instance( + shell()->web_contents()->GetSiteInstance()); + EXPECT_NE(orig_site_instance, new_site_instance); + + // Ensure that the original renderer process exited cleanly without crashing. + exit_observer.Wait(); + EXPECT_EQ(true, exit_observer.did_exit_normally()); +} + // Test that opening a new window in the same SiteInstance and then navigating // both windows to a different SiteInstance allows the first process to exit. // See http://crbug.com/126333.
diff --git a/content/browser/frame_host/render_widget_host_view_guest.cc b/content/browser/frame_host/render_widget_host_view_guest.cc index 17d22b6..5d4b65d 100644 --- a/content/browser/frame_host/render_widget_host_view_guest.cc +++ b/content/browser/frame_host/render_widget_host_view_guest.cc
@@ -167,7 +167,11 @@ void RenderWidgetHostViewGuest::RenderProcessGone( base::TerminationStatus status, int error_code) { - platform_view_->RenderProcessGone(status, error_code); + // The |platform_view_| gets destroyed before we get here if this view + // is for an InterstitialPage. + if (platform_view_) + platform_view_->RenderProcessGone(status, error_code); + // Destroy the guest view instance only, so we don't end up calling // platform_view_->Destroy(). DestroyGuestView(); @@ -209,6 +213,12 @@ } bool RenderWidgetHostViewGuest::OnMessageReceived(const IPC::Message& msg) { + if (!platform_view_) { + // In theory, we can get here if there's a delay between DestroyGuestView() + // being called and when our destructor is invoked. + return false; + } + return platform_view_->OnMessageReceived(msg); }
diff --git a/content/browser/loader/buffered_resource_handler.cc b/content/browser/loader/buffered_resource_handler.cc index 67e74a58..a38eaa915 100644 --- a/content/browser/loader/buffered_resource_handler.cc +++ b/content/browser/loader/buffered_resource_handler.cc
@@ -110,16 +110,9 @@ bool* defer) { response_ = response; - // TODO(darin): It is very odd to special-case 304 responses at this level. - // We do so only because the code always has, see r24977 and r29355. The - // fact that 204 is no longer special-cased this way suggests that 304 need - // not be special-cased either. - // - // The network stack only forwards 304 responses that were not received in - // response to a conditional request (i.e., If-Modified-Since). Other 304 - // responses end up being translated to 200 or whatever the cached response - // code happens to be. It should be very rare to see a 304 at this level. - + // A 304 response should not contain a Content-Type header (RFC 7232 section + // 4.1). The following code may incorrectly attempt to add a Content-Type to + // the response, and so must be skipped for 304 responses. if (!(response_->head.headers.get() && response_->head.headers->response_code() == 304)) { if (ShouldSniffContent()) {
diff --git a/content/browser/net/sqlite_persistent_cookie_store.cc b/content/browser/net/sqlite_persistent_cookie_store.cc index c4c6a141..24654377 100644 --- a/content/browser/net/sqlite_persistent_cookie_store.cc +++ b/content/browser/net/sqlite_persistent_cookie_store.cc
@@ -20,6 +20,7 @@ #include "base/memory/scoped_ptr.h" #include "base/metrics/field_trial.h" #include "base/metrics/histogram.h" +#include "base/profiler/scoped_tracker.h" #include "base/sequenced_task_runner.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" @@ -560,6 +561,11 @@ void SQLitePersistentCookieStore::Backend::CompleteLoadInForeground( const LoadedCallback& loaded_callback, bool load_success) { + // TODO(pkasting): Remove ScopedTracker below once crbug.com/457528 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "457528 " + "SQLitePersistentCookieStore::Backend::CompleteLoadInForeground")); Notify(loaded_callback, load_success); if (load_success)
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc index 47d0877..1ae9fe5 100644 --- a/content/browser/renderer_host/media/media_stream_manager.cc +++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -1623,15 +1623,30 @@ } void MediaStreamManager::InitializeDeviceManagersOnIOThread() { + // TODO(dalecurtis): Remove ScopedTracker below once crbug.com/457525 is + // fixed. + tracked_objects::ScopedTracker tracking_profile1( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "457525 MediaStreamManager::InitializeDeviceManagersOnIOThread 1")); DCHECK_CURRENTLY_ON(BrowserThread::IO); if (device_task_runner_.get()) return; device_task_runner_ = audio_manager_->GetWorkerTaskRunner(); + // TODO(dalecurtis): Remove ScopedTracker below once crbug.com/457525 is + // fixed. + tracked_objects::ScopedTracker tracking_profile2( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "457525 MediaStreamManager::InitializeDeviceManagersOnIOThread 2")); audio_input_device_manager_ = new AudioInputDeviceManager(audio_manager_); audio_input_device_manager_->Register(this, device_task_runner_); + // TODO(dalecurtis): Remove ScopedTracker below once crbug.com/457525 is + // fixed. + tracked_objects::ScopedTracker tracking_profile3( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "457525 MediaStreamManager::InitializeDeviceManagersOnIOThread 3")); // We want to be notified of IO message loop destruction to delete the thread // and the device managers. io_loop_ = base::MessageLoop::current(); @@ -1642,6 +1657,11 @@ audio_input_device_manager()->UseFakeDevice(); } + // TODO(dalecurtis): Remove ScopedTracker below once crbug.com/457525 is + // fixed. + tracked_objects::ScopedTracker tracking_profile4( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "457525 MediaStreamManager::InitializeDeviceManagersOnIOThread 4")); video_capture_manager_ = new VideoCaptureManager(media::VideoCaptureDeviceFactory::CreateFactory( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI)));
diff --git a/content/browser/renderer_host/media/video_capture_controller_unittest.cc b/content/browser/renderer_host/media/video_capture_controller_unittest.cc index 1cbd287..2e6299a 100644 --- a/content/browser/renderer_host/media/video_capture_controller_unittest.cc +++ b/content/browser/renderer_host/media/video_capture_controller_unittest.cc
@@ -618,6 +618,8 @@ // buffer. const size_t kScratchpadSizeInBytes = 400; unsigned char data[kScratchpadSizeInBytes]; + // Initialize memory to satisfy DrMemory tests. + memset(data, 0, kScratchpadSizeInBytes); const gfx::Size capture_resolution(10, 10); ASSERT_GE(kScratchpadSizeInBytes, capture_resolution.GetArea() * 4u) << "Scratchpad is too small to hold the largest pixel format (ARGB).";
diff --git a/content/browser/renderer_host/overscroll_controller.cc b/content/browser/renderer_host/overscroll_controller.cc index 86dc692f..0fd5e45 100644 --- a/content/browser/renderer_host/overscroll_controller.cc +++ b/content/browser/renderer_host/overscroll_controller.cc
@@ -35,11 +35,13 @@ } bool OverscrollController::WillHandleEvent(const blink::WebInputEvent& event) { - if (scroll_state_ != STATE_UNKNOWN) { + bool reset_scroll_state = false; + if (scroll_state_ != STATE_UNKNOWN || + overscroll_delta_x_ || overscroll_delta_y_) { switch (event.type) { case blink::WebInputEvent::GestureScrollEnd: case blink::WebInputEvent::GestureFlingStart: - scroll_state_ = STATE_UNKNOWN; + reset_scroll_state = true; break; case blink::WebInputEvent::MouseWheel: { @@ -48,7 +50,7 @@ if (!wheel.hasPreciseScrollingDeltas || wheel.phase == blink::WebMouseWheelEvent::PhaseEnded || wheel.phase == blink::WebMouseWheelEvent::PhaseCancelled) { - scroll_state_ = STATE_UNKNOWN; + reset_scroll_state = true; } break; } @@ -56,12 +58,15 @@ default: if (blink::WebInputEvent::isMouseEventType(event.type) || blink::WebInputEvent::isKeyboardEventType(event.type)) { - scroll_state_ = STATE_UNKNOWN; + reset_scroll_state = true; } break; } } + if (reset_scroll_state) + scroll_state_ = STATE_UNKNOWN; + if (DispatchEventCompletesAction(event)) { CompleteAction(); @@ -80,8 +85,11 @@ // Consume the event only if it updates the overscroll state. if (ProcessEventForOverscroll(event)) return true; + } else if (reset_scroll_state) { + overscroll_delta_x_ = overscroll_delta_y_ = 0.f; } + return false; }
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index 8108477..2f48c18 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -16,6 +16,7 @@ #include "base/bind_helpers.h" #include "base/callback.h" #include "base/command_line.h" +#include "base/debug/dump_without_crashing.h" #include "base/files/file.h" #include "base/lazy_instance.h" #include "base/logging.h" @@ -1578,6 +1579,11 @@ LOG(ERROR) << "bad message " << message.type() << " terminating renderer."; BrowserChildProcessHostImpl::HistogramBadMessageTerminated( PROCESS_TYPE_RENDERER); + + // Create a memory dump. This will contain enough stack frames to work out + // what the bad message was. + base::debug::DumpWithoutCrashing(); + bad_message::ReceivedBadMessage(this, bad_message::RPH_DESERIALIZATION_FAILED); }
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc index 3a7af0c..4966274 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -1218,7 +1218,7 @@ delegate_->RequestToLockMouse(user_gesture, last_unlocked_by_target); } -bool RenderViewHostImpl::IsFullscreen() const { +bool RenderViewHostImpl::IsFullscreenGranted() const { return delegate_->IsFullscreenForCurrentTab(); }
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h index 3e6b0154..470725a 100644 --- a/content/browser/renderer_host/render_view_host_impl.h +++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -327,7 +327,7 @@ void OnRenderAutoResized(const gfx::Size& size) override; void RequestToLockMouse(bool user_gesture, bool last_unlocked_by_target) override; - bool IsFullscreen() const override; + bool IsFullscreenGranted() const override; void OnFocus() override; void OnBlur() override;
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index fe0203ff..7dcae5a 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -594,7 +594,7 @@ resize_params->top_controls_shrink_blink_size = view_->DoTopControlsShrinkBlinkSize(); resize_params->visible_viewport_size = view_->GetVisibleViewportSize(); - resize_params->is_fullscreen = IsFullscreen(); + resize_params->is_fullscreen_granted = IsFullscreenGranted(); } const bool size_changed = @@ -606,7 +606,8 @@ size_changed || screen_info_out_of_date_ || old_resize_params_->physical_backing_size != resize_params->physical_backing_size || - old_resize_params_->is_fullscreen != resize_params->is_fullscreen || + old_resize_params_->is_fullscreen_granted != + resize_params->is_fullscreen_granted || old_resize_params_->top_controls_height != resize_params->top_controls_height || old_resize_params_->top_controls_shrink_blink_size != @@ -1317,7 +1318,7 @@ return view_ ? view_->IsMouseLocked() : false; } -bool RenderWidgetHostImpl::IsFullscreen() const { +bool RenderWidgetHostImpl::IsFullscreenGranted() const { return false; }
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index bea0bfa..ecd86c52 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -539,8 +539,9 @@ bool IsMouseLocked() const; - // RenderViewHost overrides this method to report when in fullscreen mode. - virtual bool IsFullscreen() const; + // RenderViewHost overrides this method to report whether tab-initiated + // fullscreen was granted. + virtual bool IsFullscreenGranted() const; // Indicates if the render widget host should track the render widget's size // as opposed to visa versa.
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc index f20df74..aba2b573 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -3324,4 +3324,49 @@ EXPECT_EQ(2U, view_->dispatcher_->processed_touch_event_count()); } +// Tests that the scroll deltas stored within the overscroll controller get +// reset at the end of the overscroll gesture even if the overscroll threshold +// isn't surpassed and the overscroll mode stays OVERSCROLL_NONE. +TEST_F(RenderWidgetHostViewAuraOverscrollTest, ScrollDeltasResetOnEnd) { + SetUpOverscrollEnvironment(); + // Wheel event scroll ending with mouse move. + SimulateWheelEvent(-30, -10, 0, true); // sent directly + SendInputEventACK(WebInputEvent::MouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); + EXPECT_EQ(-30.f, overscroll_delta_x()); + EXPECT_EQ(-10.f, overscroll_delta_y()); + SimulateMouseMove(5, 10, 0); + EXPECT_EQ(0.f, overscroll_delta_x()); + EXPECT_EQ(0.f, overscroll_delta_y()); + + // Scroll gesture. + SimulateGestureEvent(WebInputEvent::GestureScrollBegin, + blink::WebGestureDeviceTouchscreen); + SimulateGestureScrollUpdateEvent(-30, -5, 0); + SendInputEventACK(WebInputEvent::GestureScrollUpdate, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); + EXPECT_EQ(-30.f, overscroll_delta_x()); + EXPECT_EQ(-5.f, overscroll_delta_y()); + SimulateGestureEvent(WebInputEvent::GestureScrollEnd, + blink::WebGestureDeviceTouchscreen); + EXPECT_EQ(0.f, overscroll_delta_x()); + EXPECT_EQ(0.f, overscroll_delta_y()); + + // Wheel event scroll ending with a fling. + SimulateWheelEvent(5, 0, 0, true); + SendInputEventACK(WebInputEvent::MouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + SimulateWheelEvent(10, -5, 0, true); + SendInputEventACK(WebInputEvent::MouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); + EXPECT_EQ(15.f, overscroll_delta_x()); + EXPECT_EQ(-5.f, overscroll_delta_y()); + SimulateGestureFlingStartEvent(0.f, 0.1f, blink::WebGestureDeviceTouchpad); + EXPECT_EQ(0.f, overscroll_delta_x()); + EXPECT_EQ(0.f, overscroll_delta_y()); +} + } // namespace content
diff --git a/content/browser/screen_orientation/screen_orientation_browsertest.cc b/content/browser/screen_orientation/screen_orientation_browsertest.cc index 4b1d40b3..d7516cbf 100644 --- a/content/browser/screen_orientation/screen_orientation_browsertest.cc +++ b/content/browser/screen_orientation/screen_orientation_browsertest.cc
@@ -60,7 +60,7 @@ params.top_controls_height = 0.f; params.top_controls_shrink_blink_size = false; params.resizer_rect = gfx::Rect(); - params.is_fullscreen = false; + params.is_fullscreen_granted = false; rwh->Send(new ViewMsg_Resize(rwh->GetRoutingID(), params)); }
diff --git a/content/browser/service_worker/service_worker_metrics.cc b/content/browser/service_worker/service_worker_metrics.cc index 5c10a67..69f0d858 100644 --- a/content/browser/service_worker/service_worker_metrics.cc +++ b/content/browser/service_worker/service_worker_metrics.cc
@@ -4,7 +4,7 @@ #include "content/browser/service_worker/service_worker_metrics.h" -#include "base/metrics/histogram.h" +#include "base/metrics/histogram_macros.h" #include "base/metrics/user_metrics_action.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/content_browser_client.h" @@ -75,4 +75,24 @@ base::Bind(&RecordURLMetricOnUI, url)); } +void ServiceWorkerMetrics::RecordStartWorkerStatus( + ServiceWorkerStatusCode status, + bool is_installed) { + if (is_installed) { + UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.Status", status, + SERVICE_WORKER_ERROR_MAX_VALUE); + } else { + UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartNewWorker.Status", status, + SERVICE_WORKER_ERROR_MAX_VALUE); + } +} + +void ServiceWorkerMetrics::RecordStartWorkerTime(const base::TimeDelta& time, + bool is_installed) { + if (is_installed) + UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.StartWorker.Time", time); + else + UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.StartNewWorker.Time", time); +} + } // namespace content
diff --git a/content/browser/service_worker/service_worker_metrics.h b/content/browser/service_worker/service_worker_metrics.h index 8b058567..705deb7 100644 --- a/content/browser/service_worker/service_worker_metrics.h +++ b/content/browser/service_worker/service_worker_metrics.h
@@ -52,6 +52,16 @@ // Counts the number of page loads controlled by a Service Worker. static void CountControlledPageLoad(const GURL& url); + // Records the result of trying to start a worker. |is_installed| indicates + // whether the version has been installed. + static void RecordStartWorkerStatus(ServiceWorkerStatusCode status, + bool is_installed); + + // Records the time taken to successfully start a worker. |is_installed| + // indicates whether the version has been installed. + static void RecordStartWorkerTime(const base::TimeDelta& time, + bool is_installed); + private: DISALLOW_IMPLICIT_CONSTRUCTORS(ServiceWorkerMetrics); };
diff --git a/content/browser/service_worker/service_worker_storage.cc b/content/browser/service_worker/service_worker_storage.cc index 0656833..e3667294 100644 --- a/content/browser/service_worker/service_worker_storage.cc +++ b/content/browser/service_worker/service_worker_storage.cc
@@ -1451,9 +1451,11 @@ void ServiceWorkerStorage::DidCollectStaleResources( const std::vector<int64>& stale_resource_ids, ServiceWorkerDatabase::Status status) { - DCHECK_EQ(ServiceWorkerDatabase::STATUS_OK, status); - if (status != ServiceWorkerDatabase::STATUS_OK) + if (status != ServiceWorkerDatabase::STATUS_OK) { + DCHECK_NE(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, status); + ScheduleDeleteAndStartOver(); return; + } StartPurgingResources(stale_resource_ids); }
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc index 681e2b6..0c5202d 100644 --- a/content/browser/service_worker/service_worker_version.cc +++ b/content/browser/service_worker/service_worker_version.cc
@@ -19,6 +19,7 @@ #include "content/browser/service_worker/embedded_worker_registry.h" #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" +#include "content/browser/service_worker/service_worker_metrics.h" #include "content/browser/service_worker/service_worker_registration.h" #include "content/browser/service_worker/service_worker_utils.h" #include "content/browser/storage_partition_impl.h" @@ -343,6 +344,21 @@ clients->push_back(client_info); } +bool IsInstalled(ServiceWorkerVersion::Status status) { + switch (status) { + case ServiceWorkerVersion::NEW: + case ServiceWorkerVersion::INSTALLING: + case ServiceWorkerVersion::REDUNDANT: + return false; + case ServiceWorkerVersion::INSTALLED: + case ServiceWorkerVersion::ACTIVATING: + case ServiceWorkerVersion::ACTIVATED: + return true; + } + NOTREACHED() << "Unexpected status: " << status; + return false; +} + } // namespace const int ServiceWorkerVersion::kStartWorkerTimeoutMinutes = 5; @@ -1731,15 +1747,15 @@ // Failing to start a doomed worker isn't interesting and very common when // update dooms because the script is byte-to-byte identical. - if (is_doomed_) + if (is_doomed_ || status_ == REDUNDANT) return; - UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.Status", status, - SERVICE_WORKER_ERROR_MAX_VALUE); + ServiceWorkerMetrics::RecordStartWorkerStatus(status, IsInstalled(status_)); + if (status == SERVICE_WORKER_OK && !start_time.is_null() && !skip_recording_startup_time_) { - UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.StartWorker.Time", - GetTickDuration(start_time)); + ServiceWorkerMetrics::RecordStartWorkerTime(GetTickDuration(start_time), + IsInstalled(status_)); } if (status != SERVICE_WORKER_ERROR_TIMEOUT)
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc index 15bd998..3e76965 100644 --- a/content/browser/site_per_process_browsertest.cc +++ b/content/browser/site_per_process_browsertest.cc
@@ -169,21 +169,8 @@ SitePerProcessBrowserTest::SitePerProcessBrowserTest() { }; -// static -std::string SitePerProcessBrowserTest::DumpProxyHostSiteInstances( - FrameTreeNode* node) { - std::vector<std::string> sites; - for (auto& entry_pair : node->render_manager()->proxy_hosts_) { - sites.push_back(entry_pair.second->GetSiteInstance()->GetSiteURL().spec()); - } - std::sort(sites.begin(), sites.end()); - std::string result; - for (auto& site : sites) { - if (!result.empty()) - result.append("\n"); - result.append(site); - } - return result; +std::string SitePerProcessBrowserTest::DepictFrameTree(FrameTreeNode* node) { + return visualizer_.DepictFrameTree(node); } void SitePerProcessBrowserTest::StartFrameAtDataURL() { @@ -231,10 +218,16 @@ ->GetRenderWidgetHostViewsInTree(); EXPECT_EQ(1U, views_set.size()); } - RenderFrameProxyHost* proxy_to_parent = - child->render_manager()->GetRenderFrameProxyHost( - shell()->web_contents()->GetSiteInstance()); - EXPECT_FALSE(proxy_to_parent); + + EXPECT_EQ( + " Site A\n" + " |--Site A\n" + " +--Site A\n" + " |--Site A\n" + " +--Site A\n" + " +--Site A\n" + "Where A = http://127.0.0.1/", + DepictFrameTree(root)); // Load cross-site page into iframe. GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html"); @@ -259,7 +252,8 @@ ->GetRenderWidgetHostViewsInTree(); EXPECT_EQ(2U, views_set.size()); } - proxy_to_parent = child->render_manager()->GetProxyToParent(); + RenderFrameProxyHost* proxy_to_parent = + child->render_manager()->GetProxyToParent(); EXPECT_TRUE(proxy_to_parent); EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector()); // The out-of-process iframe should have its own RenderWidgetHost, @@ -269,6 +263,17 @@ proxy_to_parent->cross_process_frame_connector()->get_view_for_testing()); EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost()); + EXPECT_EQ( + " Site A ------------ proxies for B\n" + " |--Site B ------- proxies for A\n" + " +--Site A ------- proxies for B\n" + " |--Site A -- proxies for B\n" + " +--Site A -- proxies for B\n" + " +--Site A -- proxies for B\n" + "Where A = http://127.0.0.1/\n" + " B = http://foo.com/", + DepictFrameTree(root)); + // Load another cross-site page into the same iframe. url = embedded_test_server()->GetURL("bar.com", "/title3.html"); NavigateFrameToURL(root->child_at(0), url); @@ -301,6 +306,17 @@ child->current_frame_host()->render_view_host()->GetView(), proxy_to_parent->cross_process_frame_connector()->get_view_for_testing()); EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost()); + + EXPECT_EQ( + " Site A ------------ proxies for C\n" + " |--Site C ------- proxies for A\n" + " +--Site A ------- proxies for C\n" + " |--Site A -- proxies for C\n" + " +--Site A -- proxies for C\n" + " +--Site A -- proxies for C\n" + "Where A = http://127.0.0.1/\n" + " C = http://bar.com/", + DepictFrameTree(root)); } // Tests OOPIF rendering by checking that the RWH of the iframe generates @@ -418,6 +434,20 @@ bar_child->current_frame_host()->GetSiteInstance(); EXPECT_NE(shell()->web_contents()->GetSiteInstance(), bar_site_instance); +// TODO(nick): The following EXPECTs are disabled because of +// http://crbug.com/476628, where the Site C node sometimes (flakily) has +// children even though it's committed a nav to a page with no iframes. +#if 0 + EXPECT_EQ( + " Site A ------------ proxies for B C\n" + " |--Site B ------- proxies for A C\n" + " +--Site C ------- proxies for A B\n" + "Where A = http://127.0.0.1/\n" + " B = http://foo.com/\n" + " C = http://bar.com/", + DepictFrameTree(root)); +#endif + // Simulate an attempt to detach the root frame from foo_site_instance. This // should kill foo_site_instance's process. RenderFrameProxyHost* foo_mainframe_rfph = @@ -429,6 +459,17 @@ IPC::IpcSecurityTestUtil::PwnMessageReceived( foo_mainframe_rfph->GetProcess()->GetChannel(), evil_msg2); foo_terminated.Wait(); + +#if 0 + EXPECT_EQ( + " Site A ------------ proxies for B C\n" + " |--Site B ------- proxies for A C\n" + " +--Site C ------- proxies for A B\n" + "Where A = http://127.0.0.1/\n" + " B = http://foo.com/ (no process)\n" + " C = http://bar.com/", + DepictFrameTree(root)); +#endif } // Disabled for flaky crashing: crbug.com/446575 @@ -628,9 +669,8 @@ // site B and stays in not rendered state. IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NavigateRemoteFrameToKilledProcessWithSubtree) { - GURL main_url( - embedded_test_server()->GetURL( - "/frame_tree/page_with_two_frames_nested.html")); + GURL main_url(embedded_test_server()->GetURL( + "a.com", "/frame_tree/page_with_two_frames_nested.html")); NavigateToURL(shell(), main_url); // It is safe to obtain the root frame tree node here, as it doesn't change. @@ -666,24 +706,18 @@ // below, so create a local scope so we can extend the lifetime of // |site_instance_c| with a refptr. { - SiteInstance* site_instance_b = - root->child_at(0)->current_frame_host()->GetSiteInstance(); - // |site_c| will go away, so extend its lifetime with a refptr. - scoped_refptr<SiteInstanceImpl> site_instance_c = - node4->current_frame_host()->GetSiteInstance(); + // Initially each frame has proxies for the other sites. + EXPECT_EQ( + " Site A ------------ proxies for B C\n" + " |--Site B ------- proxies for A C\n" + " | +--Site C -- proxies for A B\n" + " +--Site A ------- proxies for B C\n" + "Where A = http://a.com/\n" + " B = http://bar.com/\n" + " C = http://baz.com/", + DepictFrameTree(root)); - // Initially proxies for both B and C will be present in the root and node3. - EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost( - site_instance_b)); - EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost( - site_instance_c.get())); - FrameTreeNode* node3 = root->child_at(1); - EXPECT_TRUE(node3->render_manager()->GetRenderFrameProxyHost( - site_instance_b)); - EXPECT_TRUE(node3->render_manager()->GetRenderFrameProxyHost( - site_instance_c.get())); - - // Kill that cross-site renderer/process B. + // Kill the render process for Site B. RenderProcessHost* child_process_b = root->child_at(0)->current_frame_host()->GetProcess(); RenderProcessHostWatcher crash_observer( @@ -691,24 +725,31 @@ child_process_b->Shutdown(0, false); crash_observer.Wait(); - // Make sure proxy B stays around in root and node3. - EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost( - site_instance_b)); - EXPECT_TRUE(node3->render_manager()->GetRenderFrameProxyHost( - site_instance_b)); - // Make sure proxy C goes away from root and node3. - EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost( - site_instance_c.get())); - EXPECT_FALSE(node3->render_manager()->GetRenderFrameProxyHost( - site_instance_c.get())); + // The Site C frame (a child of the crashed Site B frame) should go away, + // and there should be no remaining proxies for site C anywhere. + EXPECT_EQ( + " Site A ------------ proxies for B\n" + " |--Site B ------- proxies for A\n" + " +--Site A ------- proxies for B\n" + "Where A = http://a.com/\n" + " B = http://bar.com/ (no process)", + DepictFrameTree(root)); } - // Now navigate the second iframe (node3) to the same site as the node2. + // Now navigate the second iframe (node3) to Site B also. FrameTreeNode* node3 = root->child_at(1); GURL url = embedded_test_server()->GetURL("bar.com", "/title1.html"); NavigateFrameToURL(node3, url); EXPECT_TRUE(observer.last_navigation_succeeded()); EXPECT_EQ(url, observer.last_navigation_url()); + + EXPECT_EQ( + " Site A ------------ proxies for B\n" + " |--Site B ------- proxies for A\n" + " +--Site B ------- proxies for A\n" + "Where A = http://a.com/\n" + " B = http://bar.com/", + DepictFrameTree(root)); } // In A-embed-B-embed-C scenario, verify that killing process B clears proxies @@ -725,9 +766,8 @@ // After we kill B, make sure proxies for C are cleared. IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, KillingRendererClearsDescendantProxies) { - GURL main_url( - embedded_test_server()->GetURL( - "/frame_tree/page_with_two_frames_nested.html")); + GURL main_url(embedded_test_server()->GetURL( + "a.com", "/frame_tree/page_with_two_frames_nested.html")); NavigateToURL(shell(), main_url); // It is safe to obtain the root frame tree node here, as it doesn't change. @@ -760,40 +800,40 @@ EXPECT_EQ(site_c_url, node4->current_url()); // |site_instance_c| is expected to go away once we kill |child_process_b| - // below, so create a local scope so we can extend the lifetime of - // |site_instance_c| with a refptr. - { - SiteInstance* site_instance_b = - root->child_at(0)->current_frame_host()->GetSiteInstance(); - scoped_refptr<SiteInstanceImpl> site_instance_c = - node4->current_frame_host()->GetSiteInstance(); + // below; refcount it to extend the lifetime. + scoped_refptr<SiteInstanceImpl> site_instance_c = + node4->current_frame_host()->GetSiteInstance(); - // Initially proxies for both B and C will be present in the root. - EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost( - site_instance_b)); - EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost( - site_instance_c.get())); + // Initially proxies for both B and C will be present in the root. + EXPECT_EQ( + " Site A ------------ proxies for B C\n" + " |--Site B ------- proxies for A C\n" + " | +--Site C -- proxies for A B\n" + " +--Site A ------- proxies for B C\n" + "Where A = http://a.com/\n" + " B = http://bar.com/\n" + " C = http://baz.com/", + DepictFrameTree(root)); + // Kill process B. + RenderProcessHost* child_process_b = + root->child_at(0)->current_frame_host()->GetProcess(); + RenderProcessHostWatcher crash_observer( + child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); + child_process_b->Shutdown(0, false); + crash_observer.Wait(); - // Kill process B. - RenderProcessHost* child_process_b = - root->child_at(0)->current_frame_host()->GetProcess(); - RenderProcessHostWatcher crash_observer( - child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); - child_process_b->Shutdown(0, false); - crash_observer.Wait(); + // Make sure proxy C has gone from root. + // Make sure proxy C has gone from node3 as well. + // Make sure proxy B stays around in root and node3. + EXPECT_EQ( + " Site A ------------ proxies for B\n" + " |--Site B ------- proxies for A\n" + " +--Site A ------- proxies for B\n" + "Where A = http://a.com/\n" + " B = http://bar.com/ (no process)", + DepictFrameTree(root)); - // Make sure proxy C has gone from root. - EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost( - site_instance_c.get())); - // Make sure proxy C has gone from node3 as well. - EXPECT_FALSE(root->child_at(1)->render_manager()->GetRenderFrameProxyHost( - site_instance_c.get())); - // Make sure proxy B stays around in root and node3. - EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost( - site_instance_b)); - EXPECT_TRUE(root->child_at(1)->render_manager()->GetRenderFrameProxyHost( - site_instance_b)); - } + EXPECT_TRUE(site_instance_c->HasOneRef()); } // Crash a subframe and ensures its children are cleared from the FrameTree. @@ -866,8 +906,8 @@ // checks that if A embeds B and later adds a new subframe A2, A2 gets a proxy // in B's process. IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CreateProxiesForNewFrames) { - GURL main_url( - embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html")); + GURL main_url(embedded_test_server()->GetURL( + "b.com", "/frame_tree/page_with_one_frame.html")); EXPECT_TRUE(NavigateToURL(shell(), main_url)); // It is safe to obtain the root frame tree node here, as it doesn't change. @@ -880,19 +920,28 @@ EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"), root->child_at(0)->current_url()); + EXPECT_EQ( + " Site A ------------ proxies for B\n" + " +--Site B ------- proxies for A\n" + "Where A = http://b.com/\n" + " B = http://baz.com/", + DepictFrameTree(root)); + // Add a new child frame to the top-level frame. RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1); EXPECT_TRUE(ExecuteScript(shell()->web_contents(), "window.domAutomationController.send(" " addFrame('data:text/html,foo'));")); frame_observer.Wait(); - ASSERT_EQ(2U, root->child_count()); - // The new child frame should now have a proxy in first frame's process. - RenderFrameProxyHost* proxy = - root->child_at(1)->render_manager()->GetRenderFrameProxyHost( - root->child_at(0)->current_frame_host()->GetSiteInstance()); - EXPECT_TRUE(proxy); + // The new frame should have a proxy in Site B, for use by the old frame. + EXPECT_EQ( + " Site A ------------ proxies for B\n" + " |--Site B ------- proxies for A\n" + " +--Site A ------- proxies for B\n" + "Where A = http://b.com/\n" + " B = http://baz.com/", + DepictFrameTree(root)); } // TODO(nasko): Disable this test until out-of-process iframes is ready and the @@ -1138,10 +1187,15 @@ NavigateFrameToURL(root->child_at(0), http_url); EXPECT_EQ(http_url, observer.last_navigation_url()); EXPECT_TRUE(observer.last_navigation_succeeded()); - RenderFrameProxyHost* proxy_to_parent = - root->child_at(0)->render_manager()->GetRenderFrameProxyHost( - shell()->web_contents()->GetSiteInstance()); - EXPECT_FALSE(proxy_to_parent); + EXPECT_EQ( + " Site A\n" + " |--Site A\n" + " +--Site A\n" + " |--Site A\n" + " +--Site A\n" + " +--Site A\n" + "Where A = http://127.0.0.1/", + DepictFrameTree(root)); } // Create the cross-site URL to navigate to. @@ -1162,19 +1216,21 @@ params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK); params.frame_tree_node_id = child->frame_tree_node_id(); child->navigator()->GetController()->LoadURLWithParams(params); - EXPECT_TRUE(child->render_manager()->pending_frame_host()); site = child->render_manager()->pending_frame_host()->GetSiteInstance(); EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site); - EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(site)); - EXPECT_TRUE( - root->child_at(0)->render_manager()->GetRenderFrameProxyHost(site)); - EXPECT_FALSE(child->render_manager()->GetRenderFrameProxyHost(site)); - for (size_t i = 0; i < child->child_count(); ++i) { - EXPECT_FALSE( - child->child_at(i)->render_manager()->GetRenderFrameProxyHost(site)); - } + EXPECT_EQ( + " Site A ------------ proxies for B\n" + " |--Site A ------- proxies for B\n" + " +--Site A (B pending)\n" + " |--Site A\n" + " +--Site A\n" + " +--Site A\n" + "Where A = http://127.0.0.1/\n" + " B = http://foo.com/", + DepictFrameTree(root)); + // Now that the verification is done, run the message loop and wait for the // navigation to complete. navigation_observer.Wait(); @@ -1198,21 +1254,23 @@ params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK); params.frame_tree_node_id = child->frame_tree_node_id(); child->navigator()->GetController()->LoadURLWithParams(params); - EXPECT_TRUE(child->render_manager()->pending_frame_host() != NULL); SiteInstance* site2 = child->render_manager()->pending_frame_host()->GetSiteInstance(); EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site2); EXPECT_NE(site, site2); - EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(site2)); - EXPECT_TRUE( - root->child_at(0)->render_manager()->GetRenderFrameProxyHost(site2)); - EXPECT_FALSE(child->render_manager()->GetRenderFrameProxyHost(site2)); - for (size_t i = 0; i < child->child_count(); ++i) { - EXPECT_FALSE( - child->child_at(i)->render_manager()->GetRenderFrameProxyHost(site2)); - } + EXPECT_EQ( + " Site A ------------ proxies for B C\n" + " |--Site A ------- proxies for B C\n" + " +--Site B (C pending) -- proxies for A\n" + " |--Site A\n" + " +--Site A\n" + " +--Site A\n" + "Where A = http://127.0.0.1/\n" + " B = http://foo.com/\n" + " C = http://bar.com/", + DepictFrameTree(root)); navigation_observer.Wait(); EXPECT_TRUE(observer.last_navigation_succeeded()); @@ -1943,21 +2001,47 @@ NavigateFrameToURL(root->child_at(0), url); EXPECT_TRUE(observer.last_navigation_succeeded()); EXPECT_EQ(url, observer.last_navigation_url()); - EXPECT_EQ("http://foo.com/", DumpProxyHostSiteInstances(root)); + EXPECT_EQ( + " Site A ------------ proxies for B\n" + " |--Site B ------- proxies for A\n" + " +--Site A ------- proxies for B\n" + " |--Site A -- proxies for B\n" + " +--Site A -- proxies for B\n" + " +--Site A -- proxies for B\n" + "Where A = http://127.0.0.1/\n" + " B = http://foo.com/", + DepictFrameTree(root)); // Load another cross-site page. url = embedded_test_server()->GetURL("bar.com", "/title3.html"); NavigateIframeToURL(shell()->web_contents(), "test", url); EXPECT_TRUE(observer.last_navigation_succeeded()); EXPECT_EQ(url, observer.last_navigation_url()); - EXPECT_EQ("http://bar.com/", DumpProxyHostSiteInstances(root)); + EXPECT_EQ( + " Site A ------------ proxies for C\n" + " |--Site C ------- proxies for A\n" + " +--Site A ------- proxies for C\n" + " |--Site A -- proxies for C\n" + " +--Site A -- proxies for C\n" + " +--Site A -- proxies for C\n" + "Where A = http://127.0.0.1/\n" + " C = http://bar.com/", + DepictFrameTree(root)); // Navigate back to the parent's origin. url = embedded_test_server()->GetURL("/title1.html"); NavigateFrameToURL(child, url); EXPECT_EQ(url, observer.last_navigation_url()); EXPECT_TRUE(observer.last_navigation_succeeded()); - EXPECT_EQ("", DumpProxyHostSiteInstances(root)); + EXPECT_EQ( + " Site A\n" + " |--Site A\n" + " +--Site A\n" + " |--Site A\n" + " +--Site A\n" + " +--Site A\n" + "Where A = http://127.0.0.1/", + DepictFrameTree(root)); } } // namespace content
diff --git a/content/browser/site_per_process_browsertest.h b/content/browser/site_per_process_browsertest.h index 1e1ac4e..9e74bd7 100644 --- a/content/browser/site_per_process_browsertest.h +++ b/content/browser/site_per_process_browsertest.h
@@ -2,9 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#ifndef CONTENT_BROWSER_SITE_PER_PROCESS_BROWSERTEST_H_ +#define CONTENT_BROWSER_SITE_PER_PROCESS_BROWSERTEST_H_ + #include <string> #include "content/public/test/content_browser_test.h" +#include "content/test/content_browser_test_utils_internal.h" #include "url/gurl.h" namespace content { @@ -16,19 +20,21 @@ public: SitePerProcessBrowserTest(); - // Returns an alphabetically-sorted, newline-delimited list of the site - // instance URLs in which RenderFrameProxyHosts of |node| currently exist. - // TODO(nick): Make this a full-fledged tree walk. - static std::string DumpProxyHostSiteInstances(FrameTreeNode* node); - protected: // Start at a data URL so each extra navigation creates a navigation entry. // (The first navigation will silently be classified as AUTO_SUBFRAME.) // TODO(creis): This won't be necessary when we can wait for LOAD_STOP. void StartFrameAtDataURL(); + std::string DepictFrameTree(FrameTreeNode* node); + void SetUpCommandLine(base::CommandLine* command_line) override; void SetUpOnMainThread() override; + + private: + FrameTreeVisualizer visualizer_; }; } // namespace content + +#endif // CONTENT_BROWSER_SITE_PER_PROCESS_BROWSERTEST_H_
diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc index 869946f..55cdbc7 100644 --- a/content/browser/tracing/tracing_controller_impl.cc +++ b/content/browser/tracing/tracing_controller_impl.cc
@@ -168,6 +168,7 @@ pending_trace_log_status_ack_count_(0), maximum_trace_buffer_usage_(0), approximate_event_count_(0), + failed_memory_dump_count_(0), // Tracing may have been enabled by ContentMainRunner if kTraceStartup // is specified in command line. #if defined(OS_CHROMEOS) || defined(OS_WIN) @@ -649,7 +650,16 @@ base::trace_event::TraceLogStatus())); } } - + TraceMessageFilterSet::const_iterator it = + pending_memory_dump_filters_.find(trace_message_filter); + if (it != pending_memory_dump_filters_.end()) { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse, + base::Unretained(this), + make_scoped_refptr(trace_message_filter), + pending_memory_dump_guid_, false /* success */)); + } trace_message_filters_.erase(trace_message_filter); } @@ -890,11 +900,34 @@ base::Unretained(this), args, callback)); return; } - // TODO(primiano): send a local dump request to each of the child processes - // and do the bookkeeping to keep track of the outstanding requests. - // Also, at this point, this should check for collisions and bail out if a - // global dump is requested while another is already in progress. - NOTIMPLEMENTED(); + // Abort if another dump is already in progress. + if (pending_memory_dump_guid_) { + DVLOG(1) << "Requested memory dump " << args.dump_guid + << " while waiting for " << pending_memory_dump_guid_; + if (!callback.is_null()) + callback.Run(args.dump_guid, false /* success */); + return; + } + + pending_memory_dump_filters_.clear(); + failed_memory_dump_count_ = 0; + + base::trace_event::MemoryDumpManager::GetInstance()->CreateProcessDump(args); + + // If there are no child processes we are just done. + TraceMessageFilterSet::iterator it = trace_message_filters_.begin(); + if (it == trace_message_filters_.end()) { + if (!callback.is_null()) + callback.Run(args.dump_guid, true /* success */); + return; + } + + pending_memory_dump_guid_ = args.dump_guid; + pending_memory_dump_callback_ = callback; + pending_memory_dump_filters_ = trace_message_filters_; + + for (; it != trace_message_filters_.end(); ++it) + it->get()->SendProcessMemoryDumpRequest(args); } void TracingControllerImpl::OnProcessMemoryDumpResponse( @@ -910,11 +943,30 @@ success)); return; } - // TODO(primiano): update the bookkeeping structs and, if this was the - // response from the last pending child, fire the completion callback, which - // in turn will cause a GlobalMemoryDumpResponse message to be sent back to - // the child, if this global dump was NOT initiated by the browser. - NOTIMPLEMENTED(); + + TraceMessageFilterSet::iterator it = + pending_memory_dump_filters_.find(trace_message_filter); + + if (pending_memory_dump_guid_ != dump_guid || + it == pending_memory_dump_filters_.end()) { + DLOG(WARNING) << "Received unexpected memory dump response: " << dump_guid; + return; + } + + if (!success) + failed_memory_dump_count_++; + + pending_memory_dump_filters_.erase(it); + + if (pending_memory_dump_filters_.empty()) { + // Got response from all child proceses. + if (!pending_memory_dump_callback_.is_null()) { + const bool global_success = failed_memory_dump_count_ == 0; + pending_memory_dump_callback_.Run(dump_guid, global_success); + pending_memory_dump_callback_ = base::trace_event::MemoryDumpCallback(); + } + pending_memory_dump_guid_ = 0; + } } void TracingControllerImpl::OnMonitoringStateChanged(bool is_monitoring) {
diff --git a/content/browser/tracing/tracing_controller_impl.h b/content/browser/tracing/tracing_controller_impl.h index d22402cd..d62b514 100644 --- a/content/browser/tracing/tracing_controller_impl.h +++ b/content/browser/tracing/tracing_controller_impl.h
@@ -156,15 +156,23 @@ // Pending acks for DisableRecording. int pending_disable_recording_ack_count_; TraceMessageFilterSet pending_disable_recording_filters_; + // Pending acks for CaptureMonitoringSnapshot. int pending_capture_monitoring_snapshot_ack_count_; TraceMessageFilterSet pending_capture_monitoring_filters_; + // Pending acks for GetTraceLogStatus. int pending_trace_log_status_ack_count_; TraceMessageFilterSet pending_trace_log_status_filters_; float maximum_trace_buffer_usage_; size_t approximate_event_count_; + // Pending acks for memory RequestGlobalDumpPoint. + int failed_memory_dump_count_; + TraceMessageFilterSet pending_memory_dump_filters_; + uint64 pending_memory_dump_guid_; + base::trace_event::MemoryDumpCallback pending_memory_dump_callback_; + #if defined(OS_CHROMEOS) || defined(OS_WIN) bool is_system_tracing_; #endif
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 5a41d12..4777b22 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -722,6 +722,13 @@ SetAccessibilityMode(RemoveAccessibilityModeFrom(accessibility_mode_, mode)); } +void WebContentsImpl::RequestAXTreeSnapshot(AXTreeSnapshotCallback callback) { + // TODO(dmazzoni): http://crbug.com/475608 This only returns the + // accessibility tree from the main frame and everything in the + // same site instance. + GetMainFrame()->RequestAXTreeSnapshot(callback); +} + void WebContentsImpl::ClearNavigationTransitionData() { FrameTreeNode* node = frame_tree_.root(); node->render_manager()->ClearNavigationTransitionData();
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index df36f49e..058d96d 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -207,6 +207,12 @@ // have been removed. void RemoveAccessibilityMode(AccessibilityMode mode); + // Request a one-time snapshot of the accessibility tree without changing + // the accessibility mode. + typedef base::Callback<void(const ui::AXTreeUpdate&)> + AXTreeSnapshotCallback; + void RequestAXTreeSnapshot(AXTreeSnapshotCallback callback); + // Clear the navigation transition data when the user navigates back to Chrome // from a native app. void ClearNavigationTransitionData();
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc index 32f102d..bd12aa5 100644 --- a/content/browser/web_contents/web_contents_impl_unittest.cc +++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -1298,12 +1298,12 @@ EXPECT_EQ(orig_rfh, contents()->GetMainFrame()); // Toggle fullscreen mode on (as if initiated via IPC from renderer). - EXPECT_FALSE(orig_rvh->IsFullscreen()); + EXPECT_FALSE(orig_rvh->IsFullscreenGranted()); EXPECT_FALSE(contents()->IsFullscreenForCurrentTab()); EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents())); orig_rfh->OnMessageReceived( FrameHostMsg_ToggleFullscreen(orig_rfh->GetRoutingID(), true)); - EXPECT_TRUE(orig_rvh->IsFullscreen()); + EXPECT_TRUE(orig_rvh->IsFullscreenGranted()); EXPECT_TRUE(contents()->IsFullscreenForCurrentTab()); EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents())); @@ -1317,7 +1317,7 @@ pending_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED); // Confirm fullscreen has exited. - EXPECT_FALSE(orig_rvh->IsFullscreen()); + EXPECT_FALSE(orig_rvh->IsFullscreenGranted()); EXPECT_FALSE(contents()->IsFullscreenForCurrentTab()); EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents())); @@ -1348,7 +1348,7 @@ EXPECT_EQ(orig_rfh, contents()->GetMainFrame()); // Sanity-check: Confirm we're not starting out in fullscreen mode. - EXPECT_FALSE(orig_rvh->IsFullscreen()); + EXPECT_FALSE(orig_rvh->IsFullscreenGranted()); EXPECT_FALSE(contents()->IsFullscreenForCurrentTab()); EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents())); @@ -1356,7 +1356,7 @@ // Toggle fullscreen mode on (as if initiated via IPC from renderer). orig_rfh->OnMessageReceived( FrameHostMsg_ToggleFullscreen(orig_rfh->GetRoutingID(), true)); - EXPECT_TRUE(orig_rvh->IsFullscreen()); + EXPECT_TRUE(orig_rvh->IsFullscreenGranted()); EXPECT_TRUE(contents()->IsFullscreenForCurrentTab()); EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents())); @@ -1371,7 +1371,7 @@ orig_rfh, i + 1, url, ui::PAGE_TRANSITION_FORWARD_BACK); // Confirm fullscreen has exited. - EXPECT_FALSE(orig_rvh->IsFullscreen()); + EXPECT_FALSE(orig_rvh->IsFullscreenGranted()); EXPECT_FALSE(contents()->IsFullscreenForCurrentTab()); EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents())); } @@ -1409,12 +1409,12 @@ contents()->GetMainFrame(), 1, url, ui::PAGE_TRANSITION_TYPED); // Toggle fullscreen mode on (as if initiated via IPC from renderer). - EXPECT_FALSE(test_rvh()->IsFullscreen()); + EXPECT_FALSE(test_rvh()->IsFullscreenGranted()); EXPECT_FALSE(contents()->IsFullscreenForCurrentTab()); EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents())); contents()->GetMainFrame()->OnMessageReceived(FrameHostMsg_ToggleFullscreen( contents()->GetMainFrame()->GetRoutingID(), true)); - EXPECT_TRUE(test_rvh()->IsFullscreen()); + EXPECT_TRUE(test_rvh()->IsFullscreenGranted()); EXPECT_TRUE(contents()->IsFullscreenForCurrentTab()); EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents())); @@ -1424,7 +1424,7 @@ 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1)); // Confirm fullscreen has exited. - EXPECT_FALSE(test_rvh()->IsFullscreen()); + EXPECT_FALSE(test_rvh()->IsFullscreenGranted()); EXPECT_FALSE(contents()->IsFullscreenForCurrentTab()); EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
diff --git a/content/child/scheduler/webthread_impl_for_worker_scheduler.cc b/content/child/scheduler/webthread_impl_for_worker_scheduler.cc index bc4fe59..20379b121 100644 --- a/content/child/scheduler/webthread_impl_for_worker_scheduler.cc +++ b/content/child/scheduler/webthread_impl_for_worker_scheduler.cc
@@ -26,7 +26,9 @@ WebThreadImplForWorkerScheduler::~WebThreadImplForWorkerScheduler() { base::WaitableEvent completion(false, false); - thread_->message_loop()->PostTask( + // We need to post the shutdown task on the scheduler's task queue or tasks + // posted on the worker scheduler may not get run when the thread is deleted. + TaskRunner()->PostTask( FROM_HERE, base::Bind(&WebThreadImplForWorkerScheduler::ShutDownOnThread, base::Unretained(this), &completion)); completion.Wait();
diff --git a/content/child/scheduler/webthread_impl_for_worker_scheduler_unittest.cc b/content/child/scheduler/webthread_impl_for_worker_scheduler_unittest.cc index d8da51f..b03749a 100644 --- a/content/child/scheduler/webthread_impl_for_worker_scheduler_unittest.cc +++ b/content/child/scheduler/webthread_impl_for_worker_scheduler_unittest.cc
@@ -79,14 +79,18 @@ class WebThreadImplForWorkerSchedulerTest : public testing::Test { public: - WebThreadImplForWorkerSchedulerTest() : thread_("test thread") {} + WebThreadImplForWorkerSchedulerTest() {} ~WebThreadImplForWorkerSchedulerTest() override {} + void SetUp() override { + thread_.reset(new WebThreadImplForWorkerScheduler("test thread")); + } + void RunOnWorkerThread(const tracked_objects::Location& from_here, const base::Closure& task) { base::WaitableEvent completion(false, false); - thread_.TaskRunner()->PostTask( + thread_->TaskRunner()->PostTask( from_here, base::Bind(&WebThreadImplForWorkerSchedulerTest::RunOnWorkerThreadTask, base::Unretained(this), task, &completion)); @@ -100,7 +104,7 @@ completion->Signal(); } - WebThreadImplForWorkerScheduler thread_; + scoped_ptr<WebThreadImplForWorkerScheduler> thread_; DISALLOW_COPY_AND_ASSIGN(WebThreadImplForWorkerSchedulerTest); }; @@ -113,10 +117,23 @@ ON_CALL(*task, run()) .WillByDefault(Invoke([&completion]() { completion.Signal(); })); - thread_.postTask(blink::WebTraceLocation(), task.release()); + thread_->postTask(blink::WebTraceLocation(), task.release()); completion.Wait(); } +TEST_F(WebThreadImplForWorkerSchedulerTest, + TestTaskExecutedBeforeThreadDeletion) { + scoped_ptr<MockTask> task(new MockTask()); + base::WaitableEvent completion(false, false); + + EXPECT_CALL(*task, run()); + ON_CALL(*task, run()) + .WillByDefault(Invoke([&completion]() { completion.Signal(); })); + + thread_->postTask(blink::WebTraceLocation(), task.release()); + thread_.reset(); +} + TEST_F(WebThreadImplForWorkerSchedulerTest, TestIdleTask) { scoped_ptr<MockIdleTask> task(new MockIdleTask()); base::WaitableEvent completion(false, false); @@ -125,9 +142,9 @@ ON_CALL(*task, run(_)) .WillByDefault(Invoke([&completion](double) { completion.Signal(); })); - thread_.postIdleTask(blink::WebTraceLocation(), task.release()); + thread_->postIdleTask(blink::WebTraceLocation(), task.release()); // We need to post a wakeup task or idle work will never happen. - thread_.postDelayedTask(blink::WebTraceLocation(), new NopTask(), 50ul); + thread_->postDelayedTask(blink::WebTraceLocation(), new NopTask(), 50ul); completion.Wait(); } @@ -137,10 +154,10 @@ TestObserver observer(&calls); RunOnWorkerThread(FROM_HERE, - base::Bind(&addTaskObserver, &thread_, &observer)); - thread_.postTask(blink::WebTraceLocation(), new TestTask(&calls)); + base::Bind(&addTaskObserver, thread_.get(), &observer)); + thread_->postTask(blink::WebTraceLocation(), new TestTask(&calls)); RunOnWorkerThread(FROM_HERE, - base::Bind(&removeTaskObserver, &thread_, &observer)); + base::Bind(&removeTaskObserver, thread_.get(), &observer)); // We need to be careful what we test here. We want to make sure the // observers are un in the expected order before and after the task.
diff --git a/content/common/accessibility_messages.h b/content/common/accessibility_messages.h index 69dfb51..e7d0bcdf 100644 --- a/content/common/accessibility_messages.h +++ b/content/common/accessibility_messages.h
@@ -178,6 +178,12 @@ // and we've already reset too many times. IPC_MESSAGE_ROUTED0(AccessibilityMsg_FatalError) +// Request a one-time snapshot of the accessibility tree without +// enabling accessibility if it wasn't already enabled. The passed id +// will be returned in the AccessibilityHostMsg_SnapshotResponse message. +IPC_MESSAGE_ROUTED1(AccessibilityMsg_SnapshotTree, + int /* callback id */) + // Messages sent from the renderer to the browser. // Sent to notify the browser about renderer accessibility events. @@ -200,3 +206,10 @@ IPC_MESSAGE_ROUTED1( AccessibilityHostMsg_FindInPageResult, AccessibilityHostMsg_FindInPageResultParams) + +// Sent in response to AccessibilityMsg_SnapshotTree. The callback id that was +// passed to the request will be returned in |callback_id|, along with +// a standalone snapshot of the accessibility tree. +IPC_MESSAGE_ROUTED2(AccessibilityHostMsg_SnapshotResponse, + int /* callback_id */, + ui::AXTreeUpdate)
diff --git a/content/common/sandbox_linux/sandbox_linux.cc b/content/common/sandbox_linux/sandbox_linux.cc index 5eee4e1..b2a7b3e 100644 --- a/content/common/sandbox_linux/sandbox_linux.cc +++ b/content/common/sandbox_linux/sandbox_linux.cc
@@ -186,7 +186,12 @@ // Note: this requires SealSandbox() to be called later in this process to be // safe, as this class is keeping a file descriptor to /proc/. CHECK(sandbox::Credentials::DropFileSystemAccess(proc_fd_)); - CHECK(sandbox::Credentials::DropAllCapabilities(proc_fd_)); + + // We do not drop CAP_SYS_ADMIN because we need it to place each child process + // in its own PID namespace later on. + std::vector<sandbox::Credentials::Capability> caps; + caps.push_back(sandbox::Credentials::Capability::SYS_ADMIN); + CHECK(sandbox::Credentials::SetCapabilities(proc_fd_, caps)); // This needs to happen after moving to a new user NS, since doing so involves // writing the UID/GID map.
diff --git a/content/common/sandbox_linux/sandbox_linux.h b/content/common/sandbox_linux/sandbox_linux.h index 12aabcfc..01a0bd9a 100644 --- a/content/common/sandbox_linux/sandbox_linux.h +++ b/content/common/sandbox_linux/sandbox_linux.h
@@ -9,6 +9,7 @@ #include <vector> #include "base/basictypes.h" +#include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "content/public/common/sandbox_linux.h" @@ -118,6 +119,13 @@ // to make some vulnerabilities harder to exploit. bool LimitAddressSpace(const std::string& process_type); + // Returns a file descriptor to proc. The file descriptor is no longer valid + // after the sandbox has been sealed. + int proc_fd() const { + DCHECK_NE(-1, proc_fd_); + return proc_fd_; + } + #if defined(ANY_OF_AMTLU_SANITIZER) __sanitizer_sandbox_arguments* sanitizer_args() const { return sanitizer_args_.get();
diff --git a/content/common/view_messages.h b/content/common/view_messages.h index b8acc3ac..85134356 100644 --- a/content/common/view_messages.h +++ b/content/common/view_messages.h
@@ -470,8 +470,8 @@ IPC_STRUCT_MEMBER(gfx::Size, visible_viewport_size) // The resizer rect. IPC_STRUCT_MEMBER(gfx::Rect, resizer_rect) - // Indicates whether a page is fullscreen or not. - IPC_STRUCT_MEMBER(bool, is_fullscreen) + // Indicates whether tab-initiated fullscreen was granted. + IPC_STRUCT_MEMBER(bool, is_fullscreen_granted) // If set, requests the renderer to reply with a ViewHostMsg_UpdateRect // with the ViewHostMsg_UpdateRect_Flags::IS_RESIZE_ACK bit set in flags. IPC_STRUCT_MEMBER(bool, needs_resize_ack)
diff --git a/content/content_browser.gypi b/content/content_browser.gypi index c1726787..117d20a 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi
@@ -521,6 +521,8 @@ 'browser/device_sensors/sensor_manager_android.h', 'browser/device_sensors/sensor_manager_chromeos.cc', 'browser/device_sensors/sensor_manager_chromeos.h', + 'browser/devtools/browser_devtools_agent_host.cc', + 'browser/devtools/browser_devtools_agent_host.h', 'browser/devtools/devtools_agent_host_impl.cc', 'browser/devtools/devtools_agent_host_impl.h', 'browser/devtools/devtools_frame_trace_recorder.cc',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi index 4dd854f..93791e19 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi
@@ -186,6 +186,7 @@ 'browser/accessibility/dump_accessibility_browsertest_base.h', 'browser/accessibility/dump_accessibility_events_browsertest.cc', 'browser/accessibility/dump_accessibility_tree_browsertest.cc', + 'browser/accessibility/snapshot_ax_tree_browsertest.cc', 'browser/accessibility/site_per_process_accessibility_browsertest.cc', 'browser/battery_status/battery_monitor_impl_browsertest.cc', 'browser/battery_status/battery_monitor_integration_browsertest.cc',
diff --git a/content/public/android/java/src/org/chromium/content/browser/OWNERS b/content/public/android/java/src/org/chromium/content/browser/OWNERS index 9e085b0..66d3fd4 100644 --- a/content/public/android/java/src/org/chromium/content/browser/OWNERS +++ b/content/public/android/java/src/org/chromium/content/browser/OWNERS
@@ -9,9 +9,6 @@ # Screen Orientation API related per-file ScreenOrientation*.java=mlamouri@chromium.org -# Battery Status API related -per-file BatteryStatusManager.java=timvolodine@chromium.org - # Input handling related jdduke@chromium.org
diff --git a/content/public/android/java/src/org/chromium/content/browser/SmartClipProvider.java b/content/public/android/java/src/org/chromium/content/browser/SmartClipProvider.java index e1502b6..ae38c04 100644 --- a/content/public/android/java/src/org/chromium/content/browser/SmartClipProvider.java +++ b/content/public/android/java/src/org/chromium/content/browser/SmartClipProvider.java
@@ -6,7 +6,7 @@ import android.os.Handler; -import org.chromium.base.UsedByReflection; +import org.chromium.base.annotations.UsedByReflection; /** * An interface to provide smart clip data when requested.
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/OWNERS b/content/public/android/javatests/src/org/chromium/content/browser/OWNERS index 36b349e..966545b 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/OWNERS +++ b/content/public/android/javatests/src/org/chromium/content/browser/OWNERS
@@ -9,9 +9,6 @@ # Screen Orientation API related per-file ScreenOrientation*.java=mlamouri@chromium.org -# Battery Status API related -per-file BatteryStatusManagerTest.java=timvolodine@chromium.org - # Input handling related jdduke@chromium.org
diff --git a/content/public/browser/browser_thread.h b/content/public/browser/browser_thread.h index b3b42290..9473c2cd 100644 --- a/content/public/browser/browser_thread.h +++ b/content/public/browser/browser_thread.h
@@ -184,6 +184,16 @@ const tracked_objects::Location& from_here, const base::Closure& task); + // For use with scheduling non-critical tasks for execution after startup. + // The order or execution of tasks posted here is unspecified even when + // posting to a SequencedTaskRunner and tasks are not guaranteed to be run + // prior to browser shutdown. + // Note: see related ContentBrowserClient::PostAfterStartupTask. + static void PostAfterStartupTask( + const tracked_objects::Location& from_here, + const scoped_refptr<base::TaskRunner>& task_runner, + const base::Closure& task); + // Returns the thread pool used for blocking file I/O. Use this object to // perform random blocking operations such as file writes or querying the // Windows registry.
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc index e50b963..41feccb 100644 --- a/content/public/browser/content_browser_client.cc +++ b/content/public/browser/content_browser_client.cc
@@ -16,6 +16,13 @@ return nullptr; } +void ContentBrowserClient::PostAfterStartupTask( + const tracked_objects::Location& from_here, + const scoped_refptr<base::TaskRunner>& task_runner, + const base::Closure& task) { + task_runner->PostTask(from_here, task); +} + WebContentsViewDelegate* ContentBrowserClient::GetWebContentsViewDelegate( WebContents* web_contents) { return nullptr;
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index a0ac3c2..842169cd 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h
@@ -140,6 +140,16 @@ virtual BrowserMainParts* CreateBrowserMainParts( const MainFunctionParams& parameters); + // Allows the embedder to change the default behavior of + // BrowserThread::PostAfterStartupTask to better match whatever + // definition of "startup" the embedder has in mind. This may be + // called on any thread. + // Note: see related BrowserThread::PostAfterStartupTask. + virtual void PostAfterStartupTask( + const tracked_objects::Location& from_here, + const scoped_refptr<base::TaskRunner>& task_runner, + const base::Closure& task); + // If content creates the WebContentsView implementation, it will ask the // embedder to return an (optional) delegate to customize it. The view will // own the delegate.
diff --git a/content/public/browser/devtools_agent_host.h b/content/public/browser/devtools_agent_host.h index 49feaf1..12616c1 100644 --- a/content/public/browser/devtools_agent_host.h +++ b/content/public/browser/devtools_agent_host.h
@@ -11,10 +11,16 @@ #include "base/basictypes.h" #include "base/callback.h" #include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop_proxy.h" #include "content/common/content_export.h" #include "content/public/browser/devtools_agent_host_client.h" #include "url/gurl.h" +namespace net { +class ServerSocket; +} + namespace content { class BrowserContext; @@ -40,8 +46,17 @@ // Agent host associated with DevToolsExternalAgentProxyDelegate. TYPE_EXTERNAL, + + // Agent host associated with browser. + TYPE_BROWSER, }; + // Latest DevTools protocol version supported. + static std::string GetProtocolVersion(); + + // Returns whether particular version of DevTools protocol is supported. + static bool IsSupportedProtocolVersion(const std::string& version); + // Returns DevToolsAgentHost with a given |id| or nullptr of it doesn't exist. static scoped_refptr<DevToolsAgentHost> GetForId(const std::string& id); @@ -65,6 +80,15 @@ static scoped_refptr<DevToolsAgentHost> Create( DevToolsExternalAgentProxyDelegate* delegate); + using CreateServerSocketCallback = + base::Callback<scoped_ptr<net::ServerSocket>(std::string*)>; + + // Creates DevToolsAgentHost for the browser, which works with browser-wide + // debugging protocol. + static scoped_refptr<DevToolsAgentHost> CreateForBrowser( + scoped_refptr<base::MessageLoopProxy> tethering_message_loop, + const CreateServerSocketCallback& socket_callback); + static bool IsDebuggerAttached(WebContents* web_contents); typedef std::vector<scoped_refptr<DevToolsAgentHost> > List; @@ -103,9 +127,6 @@ // Attaches render view host to this host. virtual void ConnectWebContents(WebContents* web_contents) = 0; - // Returns true if DevToolsAgentHost is for worker. - virtual bool IsWorker() const = 0; - // Returns agent host type. virtual Type GetType() = 0;
diff --git a/content/public/browser/devtools_http_handler.h b/content/public/browser/devtools_http_handler.h index 1c79ef08..a61901b 100644 --- a/content/public/browser/devtools_http_handler.h +++ b/content/public/browser/devtools_http_handler.h
@@ -15,7 +15,6 @@ namespace net { class ServerSocket; -class URLRequestContextGetter; } namespace content {
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc index afb07ba..99c1da4d 100644 --- a/content/public/test/browser_test_utils.cc +++ b/content/public/test/browser_test_utils.cc
@@ -841,6 +841,7 @@ RenderProcessHost* render_process_host, WatchType type) : render_process_host_(render_process_host), type_(type), + did_exit_normally_(true), message_loop_runner_(new MessageLoopRunner) { render_process_host_->AddObserver(this); } @@ -849,6 +850,7 @@ WebContents* web_contents, WatchType type) : render_process_host_(web_contents->GetRenderProcessHost()), type_(type), + did_exit_normally_(true), message_loop_runner_(new MessageLoopRunner) { render_process_host_->AddObserver(this); } @@ -866,6 +868,7 @@ RenderProcessHost* host, base::TerminationStatus status, int exit_code) { + did_exit_normally_ = status == base::TERMINATION_STATUS_NORMAL_TERMINATION; if (type_ == WATCH_FOR_PROCESS_EXIT) message_loop_runner_->Quit(); }
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h index 7c2a20b..bcc424f 100644 --- a/content/public/test/browser_test_utils.h +++ b/content/public/test/browser_test_utils.h
@@ -324,6 +324,11 @@ // Waits until the renderer process exits. void Wait(); + // Returns true if a renderer process exited cleanly (without hitting + // RenderProcessExited with an abnormal TerminationStatus). This should be + // called after Wait(). + bool did_exit_normally() { return did_exit_normally_; } + private: // Overridden RenderProcessHost::LifecycleObserver methods. void RenderProcessExited(RenderProcessHost* host, @@ -333,6 +338,7 @@ RenderProcessHost* render_process_host_; WatchType type_; + bool did_exit_normally_; scoped_refptr<MessageLoopRunner> message_loop_runner_;
diff --git a/content/public/test/render_view_test.cc b/content/public/test/render_view_test.cc index 935b219..1513b8d8 100644 --- a/content/public/test/render_view_test.cc +++ b/content/public/test/render_view_test.cc
@@ -380,7 +380,7 @@ void RenderViewTest::Resize(gfx::Size new_size, gfx::Rect resizer_rect, - bool is_fullscreen) { + bool is_fullscreen_granted) { ViewMsg_Resize_Params params; params.screen_info = blink::WebScreenInfo(); params.new_size = new_size; @@ -388,7 +388,7 @@ params.top_controls_height = 0.f; params.top_controls_shrink_blink_size = false; params.resizer_rect = resizer_rect; - params.is_fullscreen = is_fullscreen; + params.is_fullscreen_granted = is_fullscreen_granted; scoped_ptr<IPC::Message> resize_message(new ViewMsg_Resize(0, params)); OnMessageReceived(*resize_message); }
diff --git a/content/renderer/accessibility/blink_ax_tree_source.cc b/content/renderer/accessibility/blink_ax_tree_source.cc index 0707716..1ad905da 100644 --- a/content/renderer/accessibility/blink_ax_tree_source.cc +++ b/content/renderer/accessibility/blink_ax_tree_source.cc
@@ -117,6 +117,10 @@ BlinkAXTreeSource::~BlinkAXTreeSource() { } +void BlinkAXTreeSource::SetRoot(blink::WebAXObject root) { + root_ = root; +} + bool BlinkAXTreeSource::IsInTree(blink::WebAXObject node) const { const blink::WebAXObject& root = GetRoot(); while (IsValid(node)) { @@ -136,6 +140,8 @@ } blink::WebAXObject BlinkAXTreeSource::GetRoot() const { + if (!root_.isNull()) + return root_; return GetMainDocument().accessibilityObject(); }
diff --git a/content/renderer/accessibility/blink_ax_tree_source.h b/content/renderer/accessibility/blink_ax_tree_source.h index b08108b..ae93ff4 100644 --- a/content/renderer/accessibility/blink_ax_tree_source.h +++ b/content/renderer/accessibility/blink_ax_tree_source.h
@@ -19,6 +19,11 @@ BlinkAXTreeSource(RenderFrameImpl* render_frame); ~BlinkAXTreeSource() override; + // It may be necessary to call SetRoot if you're using a WebScopedAXContext, + // because BlinkAXTreeSource can't get the root of the tree from the + // WebDocument if accessibility isn't enabled globally. + void SetRoot(blink::WebAXObject root); + // Call this to have BlinkAXTreeSource collect a mapping from // node ids to the frame routing id for an out-of-process iframe during // calls to SerializeNode. @@ -54,6 +59,7 @@ private: RenderFrameImpl* render_frame_; + blink::WebAXObject root_; std::map<int32, int>* node_to_frame_routing_id_map_; std::map<int32, int>* node_to_browser_plugin_instance_id_map_; int accessibility_focus_id_;
diff --git a/content/renderer/accessibility/renderer_accessibility.cc b/content/renderer/accessibility/renderer_accessibility.cc index b8152ba..12a59d3 100644 --- a/content/renderer/accessibility/renderer_accessibility.cc +++ b/content/renderer/accessibility/renderer_accessibility.cc
@@ -25,11 +25,29 @@ using blink::WebNode; using blink::WebPoint; using blink::WebRect; +using blink::WebScopedAXContext; using blink::WebSettings; using blink::WebView; namespace content { +// static +void RendererAccessibility::SnapshotAccessibilityTree( + RenderFrameImpl* render_frame, + ui::AXTreeUpdate* response) { + DCHECK(render_frame); + DCHECK(response); + if (!render_frame->GetWebFrame()) + return; + + WebDocument document = render_frame->GetWebFrame()->document(); + WebScopedAXContext context(document); + BlinkAXTreeSource tree_source(render_frame); + tree_source.SetRoot(context.root()); + ui::AXTreeSerializer<blink::WebAXObject> serializer(&tree_source); + serializer.SerializeChanges(context.root(), response); +} + RendererAccessibility::RendererAccessibility(RenderFrameImpl* render_frame) : RenderFrameObserver(render_frame), render_frame_(render_frame),
diff --git a/content/renderer/accessibility/renderer_accessibility.h b/content/renderer/accessibility/renderer_accessibility.h index be0ca59..5ab857f 100644 --- a/content/renderer/accessibility/renderer_accessibility.h +++ b/content/renderer/accessibility/renderer_accessibility.h
@@ -46,6 +46,11 @@ // (e.g., change focus, or click on a button). class CONTENT_EXPORT RendererAccessibility : public RenderFrameObserver { public: + // Request a one-time snapshot of the accessibility tree without + // enabling accessibility if it wasn't already enabled. + static void SnapshotAccessibilityTree(RenderFrameImpl* render_frame, + ui::AXTreeUpdate* response); + explicit RendererAccessibility(RenderFrameImpl* render_frame); ~RendererAccessibility() override;
diff --git a/content/renderer/media/DEPS b/content/renderer/media/DEPS new file mode 100644 index 0000000..a6cd8ed --- /dev/null +++ b/content/renderer/media/DEPS
@@ -0,0 +1,6 @@ +include_rules = [ + # For video copying, cropping and scaling. + # TODO(wuchengli): remove this when RTCVideoEncoder supports zero copy. + "+third_party/libyuv", +] +
diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc index a8188bd..77790046 100644 --- a/content/renderer/media/android/webmediaplayer_android.cc +++ b/content/renderer/media/android/webmediaplayer_android.cc
@@ -1527,48 +1527,35 @@ if (!IsKeySystemSupported(key_system)) return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported; - // We do not support run-time switching between key systems for now. - if (current_key_system_.empty()) { - if (!proxy_decryptor_) { - proxy_decryptor_.reset(new media::ProxyDecryptor( - media_permission_, - base::Bind(&WebMediaPlayerAndroid::OnKeyAdded, - weak_factory_.GetWeakPtr()), - base::Bind(&WebMediaPlayerAndroid::OnKeyError, - weak_factory_.GetWeakPtr()), - base::Bind(&WebMediaPlayerAndroid::OnKeyMessage, - weak_factory_.GetWeakPtr()))); - } + if (!proxy_decryptor_) { + DCHECK(current_key_system_.empty()); + proxy_decryptor_.reset(new media::ProxyDecryptor( + media_permission_, base::Bind(&WebMediaPlayerAndroid::OnKeyAdded, + weak_factory_.GetWeakPtr()), + base::Bind(&WebMediaPlayerAndroid::OnKeyError, + weak_factory_.GetWeakPtr()), + base::Bind(&WebMediaPlayerAndroid::OnKeyMessage, + weak_factory_.GetWeakPtr()))); GURL security_origin(frame_->document().securityOrigin().toString()); - if (!proxy_decryptor_->InitializeCDM(cdm_factory_, key_system, - security_origin)) { - return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported; - } - - // Set the CDM onto the media player. - cdm_context_ = proxy_decryptor_->GetCdmContext(); - - if (is_player_initialized_) - SetCdmInternal(base::Bind(&media::IgnoreCdmAttached)); - + proxy_decryptor_->CreateCdm( + cdm_factory_, key_system, security_origin, + base::Bind(&WebMediaPlayerAndroid::OnCdmContextReady, + weak_factory_.GetWeakPtr())); current_key_system_ = key_system; - } else if (key_system != current_key_system_) { - return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState; } + // We do not support run-time switching between key systems for now. + DCHECK(!current_key_system_.empty()); + if (key_system != current_key_system_) + return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState; + media::EmeInitDataType init_data_type = init_data_type_; if (init_data_type == media::EmeInitDataType::UNKNOWN) init_data_type = GuessInitDataType(init_data, init_data_length); - // TODO(xhwang): We assume all streams are from the same container (thus have - // the same "type") for now. In the future, the "type" should be passed down - // from the application. - if (!proxy_decryptor_->GenerateKeyRequest( - init_data_type, init_data, init_data_length)) { - current_key_system_.clear(); - return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported; - } + proxy_decryptor_->GenerateKeyRequest(init_data_type, init_data, + init_data_length); return WebMediaPlayer::MediaKeyExceptionNoError; } @@ -1772,6 +1759,20 @@ client_->didResumePlaybackBlockedForKey(); } +void WebMediaPlayerAndroid::OnCdmContextReady(media::CdmContext* cdm_context) { + DCHECK(!cdm_context_); + + if (!cdm_context) { + LOG(ERROR) << "CdmContext not available (e.g. CDM creation failed)."; + return; + } + + cdm_context_ = cdm_context; + + if (is_player_initialized_) + SetCdmInternal(base::Bind(&media::IgnoreCdmAttached)); +} + void WebMediaPlayerAndroid::SetCdmInternal( const media::CdmAttachedCB& cdm_attached_cb) { DCHECK(cdm_context_ && is_player_initialized_);
diff --git a/content/renderer/media/android/webmediaplayer_android.h b/content/renderer/media/android/webmediaplayer_android.h index 2294b7c..c1e30101 100644 --- a/content/renderer/media/android/webmediaplayer_android.h +++ b/content/renderer/media/android/webmediaplayer_android.h
@@ -318,6 +318,9 @@ MediaKeyException CancelKeyRequestInternal(const std::string& key_system, const std::string& session_id); + // Called when |cdm_context| is ready. + void OnCdmContextReady(media::CdmContext* cdm_context); + // Sets the CDM. Should only be called when |is_player_initialized_| is true // and a new non-null |cdm_context_| is available. Fires |cdm_attached_cb_| // with the result after the CDM is attached.
diff --git a/content/renderer/media/crypto/render_cdm_factory.cc b/content/renderer/media/crypto/render_cdm_factory.cc index c871f9c..e551226f 100644 --- a/content/renderer/media/crypto/render_cdm_factory.cc +++ b/content/renderer/media/crypto/render_cdm_factory.cc
@@ -4,11 +4,13 @@ #include "content/renderer/media/crypto/render_cdm_factory.h" +#include "base/bind.h" +#include "base/location.h" #include "base/logging.h" +#include "base/message_loop/message_loop_proxy.h" #include "media/base/key_systems.h" #include "media/cdm/aes_decryptor.h" #include "url/gurl.h" - #if defined(ENABLE_PEPPER_CDMS) #include "content/renderer/media/crypto/ppapi_decryptor.h" #elif defined(ENABLE_BROWSER_CDMS) @@ -37,7 +39,7 @@ DCHECK(thread_checker_.CalledOnValidThread()); } -scoped_ptr<media::MediaKeys> RenderCdmFactory::Create( +void RenderCdmFactory::Create( const std::string& key_system, bool allow_distinctive_identifier, bool allow_persistent_state, @@ -46,38 +48,45 @@ const media::SessionClosedCB& session_closed_cb, const media::LegacySessionErrorCB& legacy_session_error_cb, const media::SessionKeysChangeCB& session_keys_change_cb, - const media::SessionExpirationUpdateCB& session_expiration_update_cb) { + const media::SessionExpirationUpdateCB& session_expiration_update_cb, + const CdmCreatedCB& cdm_created_cb) { DCHECK(thread_checker_.CalledOnValidThread()); - if (!security_origin.is_valid()) - return nullptr; + if (!security_origin.is_valid()) { + base::MessageLoopProxy::current()->PostTask( + FROM_HERE, base::Bind(cdm_created_cb, nullptr)); + return; + } + + scoped_ptr<media::MediaKeys> cdm; if (media::CanUseAesDecryptor(key_system)) { // TODO(sandersd): Currently the prefixed API always allows distinctive // identifiers and persistent state. Once that changes we can sanity check // here that neither is allowed for AesDecryptor, since it does not support // them and should never be configured that way. http://crbug.com/455271 - return scoped_ptr<media::MediaKeys>( - new media::AesDecryptor(security_origin, session_message_cb, - session_closed_cb, session_keys_change_cb)); + cdm.reset(new media::AesDecryptor(security_origin, session_message_cb, + session_closed_cb, + session_keys_change_cb)); + } else { +#if defined(ENABLE_PEPPER_CDMS) + cdm = PpapiDecryptor::Create( + key_system, allow_distinctive_identifier, allow_persistent_state, + security_origin, create_pepper_cdm_cb_, session_message_cb, + session_closed_cb, legacy_session_error_cb, session_keys_change_cb, + session_expiration_update_cb); +#elif defined(ENABLE_BROWSER_CDMS) + DCHECK(allow_distinctive_identifier); + DCHECK(allow_persistent_state); + cdm = ProxyMediaKeys::Create( + key_system, security_origin, manager_, session_message_cb, + session_closed_cb, legacy_session_error_cb, session_keys_change_cb, + session_expiration_update_cb); +#endif // defined(ENABLE_PEPPER_CDMS) } -#if defined(ENABLE_PEPPER_CDMS) - return scoped_ptr<media::MediaKeys>(PpapiDecryptor::Create( - key_system, allow_distinctive_identifier, allow_persistent_state, - security_origin, create_pepper_cdm_cb_, session_message_cb, - session_closed_cb, legacy_session_error_cb, session_keys_change_cb, - session_expiration_update_cb)); -#elif defined(ENABLE_BROWSER_CDMS) - DCHECK(allow_distinctive_identifier); - DCHECK(allow_persistent_state); - return scoped_ptr<media::MediaKeys>(ProxyMediaKeys::Create( - key_system, security_origin, manager_, session_message_cb, - session_closed_cb, legacy_session_error_cb, session_keys_change_cb, - session_expiration_update_cb)); -#else - return nullptr; -#endif // defined(ENABLE_PEPPER_CDMS) + base::MessageLoopProxy::current()->PostTask( + FROM_HERE, base::Bind(cdm_created_cb, base::Passed(&cdm))); } } // namespace content
diff --git a/content/renderer/media/crypto/render_cdm_factory.h b/content/renderer/media/crypto/render_cdm_factory.h index f15bfe8a..af2d7ad 100644 --- a/content/renderer/media/crypto/render_cdm_factory.h +++ b/content/renderer/media/crypto/render_cdm_factory.h
@@ -39,7 +39,8 @@ ~RenderCdmFactory() override; - scoped_ptr<media::MediaKeys> Create( + // CdmFactory implementation. + void Create( const std::string& key_system, bool allow_distinctive_identifier, bool allow_persistent_state, @@ -48,8 +49,8 @@ const media::SessionClosedCB& session_closed_cb, const media::LegacySessionErrorCB& legacy_session_error_cb, const media::SessionKeysChangeCB& session_keys_change_cb, - const media::SessionExpirationUpdateCB& session_expiration_update_cb) - override; + const media::SessionExpirationUpdateCB& session_expiration_update_cb, + const CdmCreatedCB& cdm_created_cb) override; private: #if defined(ENABLE_PEPPER_CDMS)
diff --git a/content/renderer/media/rtc_video_encoder.cc b/content/renderer/media/rtc_video_encoder.cc index 44c9107..82e61f6 100644 --- a/content/renderer/media/rtc_video_encoder.cc +++ b/content/renderer/media/rtc_video_encoder.cc
@@ -18,6 +18,7 @@ #include "media/filters/h264_parser.h" #include "media/renderers/gpu_video_accelerator_factories.h" #include "media/video/video_encode_accelerator.h" +#include "third_party/libyuv/include/libyuv.h" #include "third_party/webrtc/system_wrappers/interface/tick_util.h" #define NOTIFY_ERROR(x) \ @@ -514,18 +515,24 @@ // Do a strided copy of the input frame to match the input requirements for // the encoder. // TODO(sheu): support zero-copy from WebRTC. http://crbug.com/269312 - media::CopyYPlane(next_frame->buffer(webrtc::kYPlane), - next_frame->stride(webrtc::kYPlane), - next_frame->height(), - frame.get()); - media::CopyUPlane(next_frame->buffer(webrtc::kUPlane), - next_frame->stride(webrtc::kUPlane), - next_frame->height(), - frame.get()); - media::CopyVPlane(next_frame->buffer(webrtc::kVPlane), - next_frame->stride(webrtc::kVPlane), - next_frame->height(), - frame.get()); + if (libyuv::I420Copy(next_frame->buffer(webrtc::kYPlane), + next_frame->stride(webrtc::kYPlane), + next_frame->buffer(webrtc::kUPlane), + next_frame->stride(webrtc::kUPlane), + next_frame->buffer(webrtc::kVPlane), + next_frame->stride(webrtc::kVPlane), + frame->data(media::VideoFrame::kYPlane), + frame->stride(media::VideoFrame::kYPlane), + frame->data(media::VideoFrame::kUPlane), + frame->stride(media::VideoFrame::kUPlane), + frame->data(media::VideoFrame::kVPlane), + frame->stride(media::VideoFrame::kVPlane), + next_frame->width(), + next_frame->height())) { + DLOG(ERROR) << "Failed to copy buffer"; + NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError); + return; + } video_encoder_->Encode(frame, next_frame_keyframe); input_buffers_free_.pop_back();
diff --git a/content/renderer/media/webrtc/DEPS b/content/renderer/media/webrtc/DEPS deleted file mode 100644 index 9d1e386..0000000 --- a/content/renderer/media/webrtc/DEPS +++ /dev/null
@@ -1,5 +0,0 @@ -include_rules = [ - # For video cropping and scaling. - "+third_party/libyuv", -] -
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc index 2d94098d..d9f9d58 100644 --- a/content/renderer/pepper/pepper_plugin_instance_impl.cc +++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -1263,7 +1263,7 @@ WebDocument document = element.document(); bool is_fullscreen_element = (element == document.fullScreenElement()); if (!view_data_.is_fullscreen && desired_fullscreen_state_ && - render_frame()->GetRenderWidget()->is_fullscreen() && + render_frame()->GetRenderWidget()->is_fullscreen_granted() && is_fullscreen_element) { // Entered fullscreen. Only possible via SetFullscreen(). view_data_.is_fullscreen = true;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 93029e3..bf54e6d 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -1049,6 +1049,8 @@ OnAddStyleSheetByURL) IPC_MESSAGE_HANDLER(FrameMsg_SetAccessibilityMode, OnSetAccessibilityMode) + IPC_MESSAGE_HANDLER(AccessibilityMsg_SnapshotTree, + OnSnapshotAccessibilityTree) IPC_MESSAGE_HANDLER(FrameMsg_DisownOpener, OnDisownOpener) IPC_MESSAGE_HANDLER(FrameMsg_CommitNavigation, OnCommitNavigation) IPC_MESSAGE_HANDLER(FrameMsg_DidUpdateSandboxFlags, OnDidUpdateSandboxFlags) @@ -1579,6 +1581,13 @@ renderer_accessibility_ = new RendererAccessibility(this); } +void RenderFrameImpl::OnSnapshotAccessibilityTree(int callback_id) { + ui::AXTreeUpdate response; + RendererAccessibility::SnapshotAccessibilityTree(this, &response); + Send(new AccessibilityHostMsg_SnapshotResponse( + routing_id_, callback_id, response)); +} + void RenderFrameImpl::OnDisownOpener() { // TODO(creis): We should only see this for main frames for now. To support // disowning the opener on subframes, we will need to move WebContentsImpl's
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index b08a73c..92e32e35 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h
@@ -643,6 +643,7 @@ void OnHideTransitionElements(const std::string& css_selector); void OnShowTransitionElements(const std::string& css_selector); void OnSetAccessibilityMode(AccessibilityMode new_mode); + void OnSnapshotAccessibilityTree(int callback_id); void OnDisownOpener(); void OnDidUpdateSandboxFlags(SandboxFlags flags); void OnTextTrackSettingsChanged(
diff --git a/content/renderer/render_frame_impl_browsertest.cc b/content/renderer/render_frame_impl_browsertest.cc index 7aeb278..633c18a6 100644 --- a/content/renderer/render_frame_impl_browsertest.cc +++ b/content/renderer/render_frame_impl_browsertest.cc
@@ -125,7 +125,7 @@ resize_params.top_controls_height = 0.f; resize_params.top_controls_shrink_blink_size = false; resize_params.resizer_rect = gfx::Rect(); - resize_params.is_fullscreen = false; + resize_params.is_fullscreen_granted = false; scoped_ptr<IPC::Message> resize_message(new ViewMsg_Resize(0, resize_params)); FrameWidget()->OnMessageReceived(*resize_message);
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 1f99730b..9a4a22c 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc
@@ -2687,7 +2687,7 @@ top_controls_height_, visible_viewport_size_, resizer_rect_, - is_fullscreen_, + is_fullscreen_granted_, NO_RESIZE_ACK); } } @@ -3695,7 +3695,7 @@ params.top_controls_shrink_blink_size = false; params.top_controls_height = 0.f; params.resizer_rect = WebRect(); - params.is_fullscreen = is_fullscreen(); + params.is_fullscreen_granted = is_fullscreen_granted(); OnResize(params); }
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc index d4792958..1b6be53 100644 --- a/content/renderer/render_widget.cc +++ b/content/renderer/render_widget.cc
@@ -269,7 +269,7 @@ void Apply(bool top_controls_shrink_blink_size, float top_controls_height, gfx::Rect resizer_rect, - bool is_fullscreen); + bool is_fullscreen_granted); RenderWidget* widget_; @@ -307,7 +307,7 @@ Apply(widget_->top_controls_shrink_blink_size_, widget_->top_controls_height_, widget_->resizer_rect_, - widget_->is_fullscreen_); + widget_->is_fullscreen_granted_); } RenderWidget::ScreenMetricsEmulator::~ScreenMetricsEmulator() { @@ -323,7 +323,7 @@ widget_->top_controls_height_, original_visible_viewport_size_, widget_->resizer_rect_, - widget_->is_fullscreen_, + widget_->is_fullscreen_granted_, NO_RESIZE_ACK); } @@ -337,14 +337,14 @@ Apply(widget_->top_controls_shrink_blink_size_, widget_->top_controls_height_, widget_->resizer_rect_, - widget_->is_fullscreen_); + widget_->is_fullscreen_granted_); } void RenderWidget::ScreenMetricsEmulator::Apply( bool top_controls_shrink_blink_size, float top_controls_height, gfx::Rect resizer_rect, - bool is_fullscreen) { + bool is_fullscreen_granted) { applied_widget_rect_.set_size(gfx::Size(params_.viewSize)); if (!applied_widget_rect_.width()) applied_widget_rect_.set_width(original_size_.width()); @@ -409,7 +409,7 @@ top_controls_height, applied_widget_rect_.size(), resizer_rect, - is_fullscreen, + is_fullscreen_granted, NO_RESIZE_ACK); } @@ -424,7 +424,7 @@ Apply(params.top_controls_shrink_blink_size, params.top_controls_height, params.resizer_rect, - params.is_fullscreen); + params.is_fullscreen_granted); if (need_ack) { widget_->set_next_paint_is_resize_ack(); @@ -479,7 +479,7 @@ did_show_(false), is_hidden_(hidden), never_visible_(never_visible), - is_fullscreen_(false), + is_fullscreen_granted_(false), has_focus_(false), handling_input_event_(false), handling_ime_event_(false), @@ -771,7 +771,7 @@ float top_controls_height, const gfx::Size& visible_viewport_size, const gfx::Rect& resizer_rect, - bool is_fullscreen, + bool is_fullscreen_granted, const ResizeAck resize_ack) { if (resizing_mode_selector_->NeverUsesSynchronousResize()) { // A resize ack shouldn't be requested if we have not ACK'd the previous @@ -795,10 +795,10 @@ resizer_rect_ = resizer_rect; // NOTE: We may have entered fullscreen mode without changing our size. - bool fullscreen_change = is_fullscreen_ != is_fullscreen; + bool fullscreen_change = is_fullscreen_granted_ != is_fullscreen_granted; if (fullscreen_change) WillToggleFullscreen(); - is_fullscreen_ = is_fullscreen; + is_fullscreen_granted_ = is_fullscreen_granted; webwidget_->setTopControlsHeight(top_controls_height, top_controls_shrink_blink_size_); @@ -843,7 +843,7 @@ top_controls_height_, new_window_rect.size(), gfx::Rect(), - is_fullscreen_, + is_fullscreen_granted_, NO_RESIZE_ACK); view_screen_rect_ = new_window_rect; window_screen_rect_ = new_window_rect; @@ -903,7 +903,7 @@ params.top_controls_height, params.visible_viewport_size, params.resizer_rect, - params.is_fullscreen, + params.is_fullscreen_granted, params.needs_resize_ack ? SEND_RESIZE_ACK : NO_RESIZE_ACK); if (orientation_changed) @@ -1841,7 +1841,7 @@ if (!webwidget_) return; - if (is_fullscreen_) { + if (is_fullscreen_granted_) { webwidget_->willExitFullScreen(); } else { webwidget_->willEnterFullScreen(); @@ -1852,7 +1852,7 @@ if (!webwidget_) return; - if (is_fullscreen_) { + if (is_fullscreen_granted_) { webwidget_->didEnterFullScreen(); } else { webwidget_->didExitFullScreen();
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h index 072da8c..6802d64e0 100644 --- a/content/renderer/render_widget.h +++ b/content/renderer/render_widget.h
@@ -123,7 +123,7 @@ blink::WebWidget* webwidget() const { return webwidget_; } gfx::Size size() const { return size_; } bool has_focus() const { return has_focus_; } - bool is_fullscreen() const { return is_fullscreen_; } + bool is_fullscreen_granted() const { return is_fullscreen_granted_; } bool is_hidden() const { return is_hidden_; } bool handling_input_event() const { return handling_input_event_; } // Temporary for debugging purposes... @@ -389,7 +389,7 @@ float top_controls_height, const gfx::Size& visible_viewport_size, const gfx::Rect& resizer_rect, - bool is_fullscreen, + bool is_fullscreen_granted, ResizeAck resize_ack); // Used to force the size of a window when running layout tests. void SetWindowRectSynchronously(const gfx::Rect& new_window_rect); @@ -659,8 +659,8 @@ // Indicates that we are never visible, so never produce graphical output. bool never_visible_; - // Indicates that we are in fullscreen mode. - bool is_fullscreen_; + // Indicates whether tab-initiated fullscreen was granted. + bool is_fullscreen_granted_; // Indicates whether we have been focused/unfocused by the browser. bool has_focus_;
diff --git a/content/renderer/render_widget_browsertest.cc b/content/renderer/render_widget_browsertest.cc index b0ed636..ab314272 100644 --- a/content/renderer/render_widget_browsertest.cc +++ b/content/renderer/render_widget_browsertest.cc
@@ -18,7 +18,7 @@ resize_params.top_controls_height = 0.f; resize_params.top_controls_shrink_blink_size = false; resize_params.resizer_rect = gfx::Rect(); - resize_params.is_fullscreen = false; + resize_params.is_fullscreen_granted = false; resize_params.needs_resize_ack = false; OnResize(resize_params); EXPECT_EQ(resize_params.needs_resize_ack, next_paint_is_resize_ack());
diff --git a/content/renderer/resizing_mode_selector.cc b/content/renderer/resizing_mode_selector.cc index d51b457..08a1cf4 100644 --- a/content/renderer/resizing_mode_selector.cc +++ b/content/renderer/resizing_mode_selector.cc
@@ -22,7 +22,7 @@ RenderWidget* widget, const ViewMsg_Resize_Params& params) { return is_synchronous_mode_ && - params.is_fullscreen == widget->is_fullscreen() && + params.is_fullscreen_granted == widget->is_fullscreen_granted() && params.screen_info.deviceScaleFactor == widget->screenInfo().deviceScaleFactor; }
diff --git a/content/shell/browser/layout_test/layout_test_devtools_frontend.cc b/content/shell/browser/layout_test/layout_test_devtools_frontend.cc index 64d8035..25ec42f8 100644 --- a/content/shell/browser/layout_test/layout_test_devtools_frontend.cc +++ b/content/shell/browser/layout_test/layout_test_devtools_frontend.cc
@@ -62,6 +62,7 @@ void LayoutTestDevToolsFrontend::ReuseFrontend(const std::string& settings, const std::string frontend_url) { DisconnectFromTarget(); + preferences()->Clear(); frontend_shell()->LoadURL(GetDevToolsPathAsURL(settings, frontend_url)); }
diff --git a/content/shell/browser/shell_devtools_frontend.cc b/content/shell/browser/shell_devtools_frontend.cc index a80490d..6d8e163 100644 --- a/content/shell/browser/shell_devtools_frontend.cc +++ b/content/shell/browser/shell_devtools_frontend.cc
@@ -224,6 +224,22 @@ new ResponseWriter(weak_factory_.GetWeakPtr(), stream_id))); fetcher->Start(); return; + } else if (method == "getPreferences") { + SendMessageAck(request_id, &preferences_); + return; + } else if (method == "setPreference") { + std::string name; + std::string value; + if (!params->GetString(0, &name) || + !params->GetString(1, &value)) { + return; + } + preferences_.SetStringWithoutPathExpansion(name, value); + } else if (method == "removePreference") { + std::string name; + if (!params->GetString(0, &name)) + return; + preferences_.RemoveWithoutPathExpansion(name, nullptr); } else { return; }
diff --git a/content/shell/browser/shell_devtools_frontend.h b/content/shell/browser/shell_devtools_frontend.h index d6ce91b..15a236e 100644 --- a/content/shell/browser/shell_devtools_frontend.h +++ b/content/shell/browser/shell_devtools_frontend.h
@@ -10,6 +10,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" +#include "base/values.h" #include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/devtools_frontend_host.h" #include "content/public/browser/web_contents_observer.h" @@ -54,6 +55,7 @@ void AgentHostClosed(DevToolsAgentHost* agent_host, bool replaced) override; void DispatchProtocolMessage(DevToolsAgentHost* agent_host, const std::string& message) override; + base::DictionaryValue* preferences() { return &preferences_; } private: // WebContentsObserver overrides @@ -78,6 +80,7 @@ scoped_ptr<DevToolsFrontendHost> frontend_host_; using PendingRequestsMap = std::map<const net::URLFetcher*, int>; PendingRequestsMap pending_requests_; + base::DictionaryValue preferences_; base::WeakPtrFactory<ShellDevToolsFrontend> weak_factory_; DISALLOW_COPY_AND_ASSIGN(ShellDevToolsFrontend);
diff --git a/content/shell/renderer/test_runner/test_interfaces.cc b/content/shell/renderer/test_runner/test_interfaces.cc index 6b88763a..a70ff059 100644 --- a/content/shell/renderer/test_runner/test_interfaces.cc +++ b/content/shell/renderer/test_runner/test_interfaces.cc
@@ -7,6 +7,8 @@ #include <string> #include "base/command_line.h" +#include "base/json/json_writer.h" +#include "base/json/string_escape.h" #include "base/logging.h" #include "base/strings/stringprintf.h" #include "content/shell/common/shell_switches.h" @@ -118,22 +120,12 @@ test_runner_->ClearDevToolsLocalStorage(); if (spec.find("/inspector/") != std::string::npos) { // Subfolder name determines default panel to open. - std::string settings = ""; std::string test_path = spec.substr(spec.find("/inspector/") + 11); - size_t slash_index = test_path.find("/"); - std::string test_path_setting = base::StringPrintf( - "\"testPath\":\"\\\"%s\\\"\"", spec.c_str()); - - // TODO(pfeldman): remove once migrated to testPath. - std::string last_active_panel; - if (slash_index != std::string::npos) { - last_active_panel = base::StringPrintf( - ",\"lastActivePanel\":\"\\\"%s\\\"\"", - test_path.substr(0, slash_index).c_str()); - } - - test_runner_->ShowDevTools(base::StringPrintf("{%s%s}", - test_path_setting.c_str(), last_active_panel.c_str()), std::string()); + base::DictionaryValue settings; + settings.SetString("testPath", base::GetQuotedJSONString(spec)); + std::string settings_string; + base::JSONWriter::Write(&settings, &settings_string); + test_runner_->ShowDevTools(settings_string, std::string()); } if (spec.find("/viewsource/") != std::string::npos) { test_runner_->setShouldEnableViewSource(true);
diff --git a/content/shell/renderer/test_runner/web_ax_object_proxy.cc b/content/shell/renderer/test_runner/web_ax_object_proxy.cc index d139fda0..019f6415 100644 --- a/content/shell/renderer/test_runner/web_ax_object_proxy.cc +++ b/content/shell/renderer/test_runner/web_ax_object_proxy.cc
@@ -488,6 +488,10 @@ .SetProperty("childrenCount", &WebAXObjectProxy::ChildrenCount) .SetProperty("selectionStart", &WebAXObjectProxy::SelectionStart) .SetProperty("selectionEnd", &WebAXObjectProxy::SelectionEnd) + .SetProperty("selectionStartLineNumber", + &WebAXObjectProxy::SelectionStartLineNumber) + .SetProperty("selectionEndLineNumber", + &WebAXObjectProxy::SelectionEndLineNumber) .SetProperty("insertionPointLineNumber", &WebAXObjectProxy::InsertionPointLineNumber) .SetProperty("selectedTextRange", &WebAXObjectProxy::SelectedTextRange) @@ -727,6 +731,17 @@ return accessibility_object_.selectionEnd(); } +int WebAXObjectProxy::SelectionStartLineNumber() { + accessibility_object_.updateLayoutAndCheckValidity(); + return accessibility_object_.selectionStartLineNumber(); +} + +int WebAXObjectProxy::SelectionEndLineNumber() { + accessibility_object_.updateLayoutAndCheckValidity(); + return accessibility_object_.selectionEndLineNumber(); +} + +// TODO(nektar): Remove this function after updating tests. int WebAXObjectProxy::InsertionPointLineNumber() { accessibility_object_.updateLayoutAndCheckValidity(); if (!accessibility_object_.isFocused()) @@ -734,6 +749,7 @@ return accessibility_object_.selectionEndLineNumber(); } +// TODO(nektar): Remove this function after updating tests. std::string WebAXObjectProxy::SelectedTextRange() { accessibility_object_.updateLayoutAndCheckValidity(); unsigned selection_start = accessibility_object_.selectionStart(); @@ -1174,7 +1190,7 @@ std::string WebAXObjectProxy::NameFrom() { accessibility_object_.updateLayoutAndCheckValidity(); - blink::WebAXNameFrom nameFrom; + blink::WebAXNameFrom nameFrom = blink::WebAXNameFromContents; blink::WebVector<blink::WebAXObject> nameObjects; accessibility_object_.name(nameFrom, nameObjects); switch(nameFrom) {
diff --git a/content/shell/renderer/test_runner/web_ax_object_proxy.h b/content/shell/renderer/test_runner/web_ax_object_proxy.h index 9a48d49..b734296 100644 --- a/content/shell/renderer/test_runner/web_ax_object_proxy.h +++ b/content/shell/renderer/test_runner/web_ax_object_proxy.h
@@ -71,7 +71,11 @@ int ChildrenCount(); int SelectionStart(); int SelectionEnd(); + int SelectionStartLineNumber(); + int SelectionEndLineNumber(); + // TODO(nektar): Remove this function after updating tests. int InsertionPointLineNumber(); + // TODO(nektar): Remove this function after updating tests. std::string SelectedTextRange(); bool IsEnabled(); bool IsRequired();
diff --git a/content/test/content_browser_test_utils_internal.cc b/content/test/content_browser_test_utils_internal.cc index 21a33d0..9097a895 100644 --- a/content/test/content_browser_test_utils_internal.cc +++ b/content/test/content_browser_test_utils_internal.cc
@@ -4,8 +4,15 @@ #include "content/test/content_browser_test_utils_internal.h" +#include <algorithm> +#include <map> +#include <set> +#include <vector> + +#include "base/strings/stringprintf.h" #include "content/browser/frame_host/frame_tree_node.h" #include "content/browser/frame_host/navigator.h" +#include "content/browser/frame_host/render_frame_proxy_host.h" #include "content/test/test_frame_navigation_observer.h" #include "url/gurl.h" @@ -20,4 +27,196 @@ observer.Wait(); } +FrameTreeVisualizer::FrameTreeVisualizer() { +} + +FrameTreeVisualizer::~FrameTreeVisualizer() { +} + +std::string FrameTreeVisualizer::DepictFrameTree(FrameTreeNode* root) { + // Tracks the sites actually used in this depiction. + std::map<std::string, SiteInstance*> legend; + + // Traversal 1: Assign names to current frames. This ensures that the first + // call to the pretty-printer will result in a naming of the site instances + // that feels natural and stable. + std::stack<FrameTreeNode*> to_explore; + for (to_explore.push(root); !to_explore.empty();) { + FrameTreeNode* node = to_explore.top(); + to_explore.pop(); + for (size_t i = node->child_count(); i-- != 0;) { + to_explore.push(node->child_at(i)); + } + + RenderFrameHost* current = node->render_manager()->current_frame_host(); + legend[GetName(current->GetSiteInstance())] = current->GetSiteInstance(); + } + + // Traversal 2: Assign names to the pending/speculative frames. For stability + // of assigned names it's important to do this before trying to name the + // proxies, which have a less well defined order. + for (to_explore.push(root); !to_explore.empty();) { + FrameTreeNode* node = to_explore.top(); + to_explore.pop(); + for (size_t i = node->child_count(); i-- != 0;) { + to_explore.push(node->child_at(i)); + } + + RenderFrameHost* pending = node->render_manager()->pending_frame_host(); + RenderFrameHost* spec = + node->render_manager()->speculative_render_frame_host_.get(); + if (pending) + legend[GetName(pending->GetSiteInstance())] = pending->GetSiteInstance(); + if (spec) + legend[GetName(spec->GetSiteInstance())] = spec->GetSiteInstance(); + } + + // Traversal 3: Assign names to the proxies and add them to |legend| too. + // Typically, only openers should have their names assigned this way. + for (to_explore.push(root); !to_explore.empty();) { + FrameTreeNode* node = to_explore.top(); + to_explore.pop(); + for (size_t i = node->child_count(); i-- != 0;) { + to_explore.push(node->child_at(i)); + } + + // Sort the proxies by SiteInstance ID to avoid hash_map ordering. + std::map<int, RenderFrameProxyHost*> sorted_proxy_hosts; + for (auto& proxy_pair : node->render_manager()->proxy_hosts_) { + sorted_proxy_hosts.insert(proxy_pair); + } + for (auto& proxy_pair : sorted_proxy_hosts) { + RenderFrameProxyHost* proxy = proxy_pair.second; + legend[GetName(proxy->GetSiteInstance())] = proxy->GetSiteInstance(); + } + } + + // Traversal 4: Now that all names are assigned, make a big loop to pretty- + // print the tree. Each iteration produces exactly one line of format. + std::string result; + for (to_explore.push(root); !to_explore.empty();) { + FrameTreeNode* node = to_explore.top(); + to_explore.pop(); + for (size_t i = node->child_count(); i-- != 0;) { + to_explore.push(node->child_at(i)); + } + + // Draw the feeler line tree graphics by walking up to the root. A feeler + // line is needed for each ancestor that is the last child of its parent. + // This creates the ASCII art that looks like: + // Foo + // |--Foo + // |--Foo + // | |--Foo + // | +--Foo + // | +--Foo + // +--Foo + // +--Foo + // + // TODO(nick): Make this more elegant. + std::string line; + if (node != root) { + if (node->parent()->child_at(node->parent()->child_count() - 1) != node) + line = " |--"; + else + line = " +--"; + for (FrameTreeNode* up = node->parent(); up != root; up = up->parent()) { + if (up->parent()->child_at(up->parent()->child_count() - 1) != up) + line = " | " + line; + else + line = " " + line; + } + } + + // Prefix one extra space of padding for two reasons. First, this helps the + // diagram aligns nicely with the legend. Second, this makes it easier to + // read the diffs that gtest spits out on EXPECT_EQ failure. + line = " " + line; + + // Summarize the FrameTreeNode's state. Always show the site of the current + // RenderFrameHost, and show any exceptional state of the node, like a + // pending or speculative RenderFrameHost. + RenderFrameHost* current = node->render_manager()->current_frame_host(); + RenderFrameHost* pending = node->render_manager()->pending_frame_host(); + RenderFrameHost* spec = + node->render_manager()->speculative_render_frame_host_.get(); + base::StringAppendF(&line, "Site %s", + GetName(current->GetSiteInstance()).c_str()); + if (pending) { + base::StringAppendF(&line, " (%s pending)", + GetName(pending->GetSiteInstance()).c_str()); + } + if (spec) { + base::StringAppendF(&line, " (%s speculative)", + GetName(spec->GetSiteInstance()).c_str()); + } + + // Show the SiteInstances of the RenderFrameProxyHosts of this node. + if (!node->render_manager()->proxy_hosts_.empty()) { + // Show a dashed line of variable length before the proxy list. Always at + // least two dashes. + line.append(" --"); + + // To make proxy lists align vertically for the first three tree levels, + // pad with dashes up to a first tab stop at column 19 (which works out to + // text editor column 28 in the typical diagram fed to EXPECT_EQ as a + // string literal). Lining the lists up vertically makes differences in + // the proxy sets easier to spot visually. We choose not to use the + // *actual* tree height here, because that would make the diagram's + // appearance less stable as the tree's shape evolves. + while (line.length() < 20) { + line.append("-"); + } + line.append(" proxies for"); + + // Sort these alphabetically, to avoid hash_map ordering dependency. + std::vector<std::string> sorted_proxy_hosts; + for (auto& proxy_pair : node->render_manager()->proxy_hosts_) { + sorted_proxy_hosts.push_back( + GetName(proxy_pair.second->GetSiteInstance())); + } + std::sort(sorted_proxy_hosts.begin(), sorted_proxy_hosts.end()); + for (std::string& proxy_name : sorted_proxy_hosts) { + base::StringAppendF(&line, " %s", proxy_name.c_str()); + } + } + if (node != root) + result.append("\n"); + result.append(line); + } + + // Finally, show a legend with details of the site instances. + const char* prefix = "Where "; + for (auto& legend_entry : legend) { + SiteInstanceImpl* site_instance = + static_cast<SiteInstanceImpl*>(legend_entry.second); + base::StringAppendF(&result, "\n%s%s = %s", prefix, + legend_entry.first.c_str(), + site_instance->GetSiteURL().spec().c_str()); + // Highlight some exceptionable conditions. + if (site_instance->active_frame_count() == 0) + result.append(" (active_frame_count == 0)"); + if (!site_instance->GetProcess()->HasConnection()) + result.append(" (no process)"); + prefix = " "; + } + return result; +} + +std::string FrameTreeVisualizer::GetName(SiteInstance* site_instance) { + // Indices into the vector correspond to letters of the alphabet. + size_t index = + std::find(seen_site_instance_ids_.begin(), seen_site_instance_ids_.end(), + site_instance->GetId()) - + seen_site_instance_ids_.begin(); + if (index == seen_site_instance_ids_.size()) + seen_site_instance_ids_.push_back(site_instance->GetId()); + + // Whosoever writes a test using >=26 site instances shall be a lucky ducky. + if (index < 25) + return base::StringPrintf("%c", 'A' + static_cast<char>(index)); + else + return base::StringPrintf("Z%d", static_cast<int>(index - 25)); +} + } // namespace content
diff --git a/content/test/content_browser_test_utils_internal.h b/content/test/content_browser_test_utils_internal.h index a27aea58..4486d14 100644 --- a/content/test/content_browser_test_utils_internal.h +++ b/content/test/content_browser_test_utils_internal.h
@@ -5,21 +5,66 @@ #ifndef CONTENT_TEST_CONTENT_BROWSER_TEST_UTILS_INTERNAL_H_ #define CONTENT_TEST_CONTENT_BROWSER_TEST_UTILS_INTERNAL_H_ -// A collections of functions designed for use with content_shell based browser +// A collection of functions designed for use with content_shell based browser // tests internal to the content/ module. // Note: If a function here also works with browser_tests, it should be in // the content public API. +#include <string> +#include <vector> + +#include "base/basictypes.h" + class GURL; namespace content { class FrameTreeNode; +class SiteInstance; // Navigates the frame represented by |node| to |url|, blocking until the // navigation finishes. void NavigateFrameToURL(FrameTreeNode* node, const GURL& url); +// Creates compact textual representations of the state of the frame tree that +// is appropriate for use in assertions. +// +// The diagrams show frame tree structure, the SiteInstance of current frames, +// presence of pending frames, and the SiteInstances of any and all proxies. +// They look like this: +// +// Site A (D pending) -- proxies for B C +// |--Site B --------- proxies for A C +// +--Site C --------- proxies for B A +// |--Site A ---- proxies for B +// +--Site A ---- proxies for B +// +--Site A -- proxies for B +// Where A = http://127.0.0.1/ +// B = http://foo.com/ (no process) +// C = http://bar.com/ +// D = http://next.com/ +// +// SiteInstances are assigned single-letter names (A, B, C) which are remembered +// across invocations of the pretty-printer. +class FrameTreeVisualizer { + public: + FrameTreeVisualizer(); + ~FrameTreeVisualizer(); + + // Formats and returns a diagram for the provided FrameTreeNode. + std::string DepictFrameTree(FrameTreeNode* root); + + private: + // Assign or retrive the abbreviated short name (A, B, C) for a site instance. + std::string GetName(SiteInstance* site_instance); + + // Elements are site instance ids. The index of the SiteInstance in the vector + // determines the abbreviated name (0->A, 1->B) for that SiteInstance. + std::vector<int> seen_site_instance_ids_; + + DISALLOW_COPY_AND_ASSIGN(FrameTreeVisualizer); +}; + } // namespace content #endif // CONTENT_TEST_CONTENT_BROWSER_TEST_UTILS_INTERNAL_H_
diff --git a/content/test/data/post_message.html b/content/test/data/post_message.html index e111fea..fdec3e3 100644 --- a/content/test/data/post_message.html +++ b/content/test/data/post_message.html
@@ -34,6 +34,12 @@ return true; } + function registerUnload() { + window.addEventListener('unload', function(e) { + postToParent("message-from-unload", "*"); + }); + } + // Listen to incoming messages. var receivedMessages = 0; var receivedMessagesWithPort = 0;
diff --git a/content/test/test_render_view_host.cc b/content/test/test_render_view_host.cc index 5380c93..2ffee6c9 100644 --- a/content/test/test_render_view_host.cc +++ b/content/test/test_render_view_host.cc
@@ -249,8 +249,8 @@ return render_view_created_; } -bool TestRenderViewHost::IsFullscreen() const { - return RenderViewHostImpl::IsFullscreen(); +bool TestRenderViewHost::IsFullscreenGranted() const { + return RenderViewHostImpl::IsFullscreenGranted(); } void TestRenderViewHost::SimulateWasHidden() {
diff --git a/content/test/test_render_view_host.h b/content/test/test_render_view_host.h index c7a75a3..9ef744ff 100644 --- a/content/test/test_render_view_host.h +++ b/content/test/test_render_view_host.h
@@ -241,7 +241,7 @@ int32 max_page_id, bool window_was_created_with_opener) override; bool IsRenderViewLive() const override; - bool IsFullscreen() const override; + bool IsFullscreenGranted() const override; private: FRIEND_TEST_ALL_PREFIXES(RenderViewHostTest, FilterNavigate);
diff --git a/content/zygote/zygote_linux.cc b/content/zygote/zygote_linux.cc index 5944f87..5a84dec6 100644 --- a/content/zygote/zygote_linux.cc +++ b/content/zygote/zygote_linux.cc
@@ -36,6 +36,8 @@ #include "content/public/common/zygote_fork_delegate_linux.h" #include "ipc/ipc_channel.h" #include "ipc/ipc_switches.h" +#include "sandbox/linux/services/credentials.h" +#include "sandbox/linux/services/namespace_sandbox.h" // See http://code.google.com/p/chromium/wiki/LinuxZygote @@ -47,6 +49,14 @@ void SIGCHLDHandler(int signal) { } +// On Linux, when a process is the init process of a PID namespace, it cannot be +// terminated by signals like SIGTERM or SIGINT, since they are ignored unless +// we register a handler for them. In the handlers, we exit with this special +// exit code that GetTerminationStatus understands to mean that we were +// terminated by an external signal. +const int kKilledExitCode = 0x80; +const int kUnexpectedExitCode = 0x81; + int LookUpFd(const base::GlobalDescriptors::Mapping& fd_mapping, uint32_t key) { for (size_t index = 0; index < fd_mapping.size(); ++index) { if (fd_mapping[index].key == key) @@ -104,7 +114,7 @@ struct sigaction action; memset(&action, 0, sizeof(action)); action.sa_handler = &SIGCHLDHandler; - CHECK(sigaction(SIGCHLD, &action, NULL) == 0); + PCHECK(sigaction(SIGCHLD, &action, NULL) == 0); if (UsingSUIDSandbox() || UsingNSSandbox()) { // Let the ZygoteHost know we are ready to go. @@ -305,6 +315,11 @@ // Time to forget about this process. process_info_map_.erase(real_pid); } + + if (WIFEXITED(*exit_code) && WEXITSTATUS(*exit_code) == kKilledExitCode) { + *status = base::TERMINATION_STATUS_PROCESS_WAS_KILLED; + } + return true; } @@ -375,12 +390,33 @@ CHECK_NE(pid, 0); } else { CreatePipe(&read_pipe, &write_pipe); - // This is roughly equivalent to a fork(). We are using ForkWithFlags mainly - // to give it some more diverse test coverage. - pid = base::ForkWithFlags(SIGCHLD, nullptr, nullptr); + if (sandbox_flags_ & kSandboxLinuxPIDNS && + sandbox_flags_ & kSandboxLinuxUserNS) { + pid = sandbox::NamespaceSandbox::ForkInNewPidNamespace( + /*drop_capabilities_in_child=*/true); + } else { + pid = fork(); + } } if (pid == 0) { + // If the process is the init process inside a PID namespace, it must have + // explicit signal handlers. + if (getpid() == 1) { + for (const int sig : {SIGINT, SIGTERM}) { + sandbox::NamespaceSandbox::InstallTerminationSignalHandler( + sig, kKilledExitCode); + } + + static const int kUnexpectedSignals[] = { + SIGHUP, SIGQUIT, SIGABRT, SIGPIPE, SIGUSR1, SIGUSR2, + }; + for (const int sig : kUnexpectedSignals) { + sandbox::NamespaceSandbox::InstallTerminationSignalHandler( + sig, kUnexpectedExitCode); + } + } + // In the child process. write_pipe.reset();
diff --git a/content/zygote/zygote_main_linux.cc b/content/zygote/zygote_main_linux.cc index 8a03e4e..ab12e5b 100644 --- a/content/zygote/zygote_main_linux.cc +++ b/content/zygote/zygote_main_linux.cc
@@ -40,6 +40,7 @@ #include "content/public/common/zygote_fork_delegate_linux.h" #include "content/zygote/zygote_linux.h" #include "crypto/nss_util.h" +#include "sandbox/linux/services/credentials.h" #include "sandbox/linux/services/init_process_reaper.h" #include "sandbox/linux/services/libc_urandom_override.h" #include "sandbox/linux/services/namespace_sandbox.h" @@ -80,6 +81,11 @@ } } +void RunTwoClosures(const base::Closure* first, const base::Closure* second) { + first->Run(); + second->Run(); +} + } // namespace // See http://code.google.com/p/chromium/wiki/LinuxZygote @@ -407,12 +413,20 @@ return true; } +static void DropAllCapabilities(int proc_fd) { + CHECK(sandbox::Credentials::DropAllCapabilities(proc_fd)); +} + static void EnterNamespaceSandbox(LinuxSandbox* linux_sandbox, base::Closure* post_fork_parent_callback) { linux_sandbox->EngageNamespaceSandbox(); if (getpid() == 1) { - CHECK(CreateInitProcessReaper(post_fork_parent_callback)); + base::Closure drop_all_caps_callback = + base::Bind(&DropAllCapabilities, linux_sandbox->proc_fd()); + base::Closure callback = base::Bind( + &RunTwoClosures, &drop_all_caps_callback, post_fork_parent_callback); + CHECK(CreateInitProcessReaper(&callback)); } }
diff --git a/device/BUILD.gn b/device/BUILD.gn index bd83abe..3bf6fa7 100644 --- a/device/BUILD.gn +++ b/device/BUILD.gn
@@ -20,6 +20,7 @@ "bluetooth/bluetooth_chromeos_unittest.cc", "bluetooth/bluetooth_device_unittest.cc", "bluetooth/bluetooth_device_win_unittest.cc", + "bluetooth/bluetooth_discovery_filter_unittest.cc", "bluetooth/bluetooth_gatt_chromeos_unittest.cc", "bluetooth/bluetooth_low_energy_win_unittest.cc", "bluetooth/bluetooth_service_record_win_unittest.cc",
diff --git a/device/bluetooth/bluetooth_adapter.cc b/device/bluetooth/bluetooth_adapter.cc index 52c2d74..fd2e29b3 100644 --- a/device/bluetooth/bluetooth_adapter.cc +++ b/device/bluetooth/bluetooth_adapter.cc
@@ -42,14 +42,70 @@ return weak_ptr_factory_.GetWeakPtr(); } +void BluetoothAdapter::StartDiscoverySessionWithFilter( + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter, + const DiscoverySessionCallback& callback, + const ErrorCallback& error_callback) { + AddDiscoverySession(discovery_filter.get(), + base::Bind(&BluetoothAdapter::OnStartDiscoverySession, + weak_ptr_factory_.GetWeakPtr(), + base::Passed(&discovery_filter), callback), + error_callback); +} + void BluetoothAdapter::StartDiscoverySession( const DiscoverySessionCallback& callback, const ErrorCallback& error_callback) { - AddDiscoverySession( - base::Bind(&BluetoothAdapter::OnStartDiscoverySession, - weak_ptr_factory_.GetWeakPtr(), - callback), - error_callback); + StartDiscoverySessionWithFilter(nullptr, callback, error_callback); +} + +scoped_ptr<BluetoothDiscoveryFilter> +BluetoothAdapter::GetMergedDiscoveryFilterHelper( + const BluetoothDiscoveryFilter* masked_filter, + bool omit) const { + scoped_ptr<BluetoothDiscoveryFilter> result; + bool first_merge = true; + + std::set<BluetoothDiscoverySession*> temp(discovery_sessions_); + for (const auto& iter : temp) { + const BluetoothDiscoveryFilter* curr_filter = iter->GetDiscoveryFilter(); + + if (!iter->IsActive()) + continue; + + if (omit && curr_filter == masked_filter) { + // if masked_filter is pointing to empty filter, and there are + // multiple empty filters in discovery_sessions_, make sure we'll + // process next empty sessions. + omit = false; + continue; + } + + if (first_merge) { + first_merge = false; + if (curr_filter) { + result.reset(new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_DUAL)); + result->CopyFrom(*curr_filter); + } + continue; + } + + result = BluetoothDiscoveryFilter::Merge(result.get(), curr_filter); + } + + return result.Pass(); +} + +scoped_ptr<BluetoothDiscoveryFilter> +BluetoothAdapter::GetMergedDiscoveryFilter() const { + return GetMergedDiscoveryFilterHelper(nullptr, false); +} + +scoped_ptr<BluetoothDiscoveryFilter> +BluetoothAdapter::GetMergedDiscoveryFilterMasked( + BluetoothDiscoveryFilter* masked_filter) const { + return GetMergedDiscoveryFilterHelper(masked_filter, true); } BluetoothAdapter::DeviceList BluetoothAdapter::GetDevices() { @@ -128,10 +184,12 @@ } void BluetoothAdapter::OnStartDiscoverySession( + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter, const DiscoverySessionCallback& callback) { VLOG(1) << "Discovery session started!"; scoped_ptr<BluetoothDiscoverySession> discovery_session( - new BluetoothDiscoverySession(scoped_refptr<BluetoothAdapter>(this))); + new BluetoothDiscoverySession(scoped_refptr<BluetoothAdapter>(this), + discovery_filter.Pass())); discovery_sessions_.insert(discovery_session.get()); callback.Run(discovery_session.Pass()); }
diff --git a/device/bluetooth/bluetooth_adapter.h b/device/bluetooth/bluetooth_adapter.h index 77c64ee..d764ae97 100644 --- a/device/bluetooth/bluetooth_adapter.h +++ b/device/bluetooth/bluetooth_adapter.h
@@ -20,6 +20,7 @@ namespace device { +class BluetoothDiscoveryFilter; class BluetoothDiscoverySession; class BluetoothGattCharacteristic; class BluetoothGattDescriptor; @@ -273,6 +274,19 @@ DiscoverySessionCallback; virtual void StartDiscoverySession(const DiscoverySessionCallback& callback, const ErrorCallback& error_callback); + virtual void StartDiscoverySessionWithFilter( + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter, + const DiscoverySessionCallback& callback, + const ErrorCallback& error_callback); + + // Return all discovery filters assigned to this adapter merged together. + scoped_ptr<BluetoothDiscoveryFilter> GetMergedDiscoveryFilter() const; + + // Works like GetMergedDiscoveryFilter, but doesn't take |masked_filter| into + // account. |masked_filter| is compared by pointer, and must be a member of + // active session. + scoped_ptr<BluetoothDiscoveryFilter> GetMergedDiscoveryFilterMasked( + BluetoothDiscoveryFilter* masked_filter) const; // Requests the list of devices from the adapter. All devices are returned, // including those currently connected and those paired. Use the returned @@ -395,12 +409,22 @@ // - If the count is greater than 1, decrement the count and return // success. // + // |discovery_filter| passed to AddDiscoverySession and RemoveDiscoverySession + // is owned by other objects and shall not be freed. + // // These methods invoke |callback| for success and |error_callback| for // failures. - virtual void AddDiscoverySession(const base::Closure& callback, + virtual void AddDiscoverySession(BluetoothDiscoveryFilter* discovery_filter, + const base::Closure& callback, const ErrorCallback& error_callback) = 0; - virtual void RemoveDiscoverySession(const base::Closure& callback, - const ErrorCallback& error_callback) = 0; + virtual void RemoveDiscoverySession( + BluetoothDiscoveryFilter* discovery_filter, + const base::Closure& callback, + const ErrorCallback& error_callback) = 0; + virtual void SetDiscoveryFilter( + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter, + const base::Closure& callback, + const ErrorCallback& error_callback) = 0; // Called by RemovePairingDelegate() in order to perform any class-specific // internal functionality necessary to remove the pairing delegate, such as @@ -409,7 +433,9 @@ BluetoothDevice::PairingDelegate* pairing_delegate) = 0; // Success callback passed to AddDiscoverySession by StartDiscoverySession. - void OnStartDiscoverySession(const DiscoverySessionCallback& callback); + void OnStartDiscoverySession( + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter, + const DiscoverySessionCallback& callback); // Marks all known DiscoverySession instances as inactive. Called by // BluetoothAdapter in the event that the adapter unexpectedly stops @@ -435,6 +461,12 @@ std::list<PairingDelegatePair> pairing_delegates_; private: + // Return all discovery filters assigned to this adapter merged together. + // If |omit| is true, |discovery_filter| will not be processed. + scoped_ptr<BluetoothDiscoveryFilter> GetMergedDiscoveryFilterHelper( + const BluetoothDiscoveryFilter* discovery_filter, + bool omit) const; + // List of active DiscoverySession objects. This is used to notify sessions to // become inactive in case of an unexpected change to the adapter discovery // state. We keep raw pointers, with the invariant that a DiscoverySession
diff --git a/device/bluetooth/bluetooth_adapter_chromeos.cc b/device/bluetooth/bluetooth_adapter_chromeos.cc index edd0f01..fce8f8b 100644 --- a/device/bluetooth/bluetooth_adapter_chromeos.cc +++ b/device/bluetooth/bluetooth_adapter_chromeos.cc
@@ -36,6 +36,7 @@ using device::BluetoothAdapter; using device::BluetoothAudioSink; using device::BluetoothDevice; +using device::BluetoothDiscoveryFilter; using device::BluetoothSocket; using device::BluetoothUUID; @@ -1091,6 +1092,7 @@ } void BluetoothAdapterChromeOS::AddDiscoverySession( + BluetoothDiscoveryFilter* discovery_filter, const base::Closure& callback, const ErrorCallback& error_callback) { if (!IsPresent()) { @@ -1131,6 +1133,7 @@ } void BluetoothAdapterChromeOS::RemoveDiscoverySession( + BluetoothDiscoveryFilter* discovery_filter, const base::Closure& callback, const ErrorCallback& error_callback) { if (!IsPresent()) { @@ -1181,6 +1184,13 @@ error_callback)); } +void BluetoothAdapterChromeOS::SetDiscoveryFilter( + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter, + const base::Closure& callback, + const ErrorCallback& error_callback) { + // TODO(jpawlowski): Implement +} + void BluetoothAdapterChromeOS::OnStartDiscovery( const base::Closure& callback, const ErrorCallback& error_callback) { @@ -1263,7 +1273,7 @@ VLOG(1) << "Process queued discovery request."; DiscoveryCallbackPair callbacks = discovery_request_queue_.front(); discovery_request_queue_.pop(); - AddDiscoverySession(callbacks.first, callbacks.second); + AddDiscoverySession(nullptr, callbacks.first, callbacks.second); // If the queued request resulted in a pending call, then let it // asynchonously process the remaining queued requests once the pending
diff --git a/device/bluetooth/bluetooth_adapter_chromeos.h b/device/bluetooth/bluetooth_adapter_chromeos.h index d8c1d9b..39a23dec2 100644 --- a/device/bluetooth/bluetooth_adapter_chromeos.h +++ b/device/bluetooth/bluetooth_adapter_chromeos.h
@@ -23,6 +23,7 @@ #include "device/bluetooth/bluetooth_adapter.h" #include "device/bluetooth/bluetooth_audio_sink.h" #include "device/bluetooth/bluetooth_device.h" +#include "device/bluetooth/bluetooth_discovery_session.h" #include "device/bluetooth/bluetooth_export.h" namespace device { @@ -263,10 +264,17 @@ bool success); // BluetoothAdapter: - void AddDiscoverySession(const base::Closure& callback, + void AddDiscoverySession(device::BluetoothDiscoveryFilter* discovery_filter, + const base::Closure& callback, const ErrorCallback& error_callback) override; - void RemoveDiscoverySession(const base::Closure& callback, - const ErrorCallback& error_callback) override; + void RemoveDiscoverySession( + device::BluetoothDiscoveryFilter* discovery_filter, + const base::Closure& callback, + const ErrorCallback& error_callback) override; + void SetDiscoveryFilter( + scoped_ptr<device::BluetoothDiscoveryFilter> discovery_filter, + const base::Closure& callback, + const ErrorCallback& error_callback) override; // Called by dbus:: on completion of the D-Bus method call to start discovery. void OnStartDiscovery(const base::Closure& callback,
diff --git a/device/bluetooth/bluetooth_adapter_mac.h b/device/bluetooth/bluetooth_adapter_mac.h index 52567b04..bca4389 100644 --- a/device/bluetooth/bluetooth_adapter_mac.h +++ b/device/bluetooth/bluetooth_adapter_mac.h
@@ -95,10 +95,15 @@ // BluetoothAdapter: void DeleteOnCorrectThread() const override; - void AddDiscoverySession(const base::Closure& callback, + void AddDiscoverySession(BluetoothDiscoveryFilter* discovery_filter, + const base::Closure& callback, const ErrorCallback& error_callback) override; - void RemoveDiscoverySession(const base::Closure& callback, + void RemoveDiscoverySession(BluetoothDiscoveryFilter* discovery_filter, + const base::Closure& callback, const ErrorCallback& error_callback) override; + void SetDiscoveryFilter(scoped_ptr<BluetoothDiscoveryFilter> discovery_filter, + const base::Closure& callback, + const ErrorCallback& error_callback) override; void Init(); void InitForTest(scoped_refptr<base::SequencedTaskRunner> ui_task_runner);
diff --git a/device/bluetooth/bluetooth_adapter_mac.mm b/device/bluetooth/bluetooth_adapter_mac.mm index fc75414..7c04a433 100644 --- a/device/bluetooth/bluetooth_adapter_mac.mm +++ b/device/bluetooth/bluetooth_adapter_mac.mm
@@ -180,6 +180,7 @@ } void BluetoothAdapterMac::AddDiscoverySession( + BluetoothDiscoveryFilter* discovery_filter, const base::Closure& callback, const ErrorCallback& error_callback) { DVLOG(1) << __func__; @@ -207,6 +208,7 @@ } void BluetoothAdapterMac::RemoveDiscoverySession( + BluetoothDiscoveryFilter* discovery_filter, const base::Closure& callback, const ErrorCallback& error_callback) { DVLOG(1) << __func__; @@ -236,6 +238,14 @@ callback.Run(); } +void BluetoothAdapterMac::SetDiscoveryFilter( + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter, + const base::Closure& callback, + const ErrorCallback& error_callback) { + NOTIMPLEMENTED(); + error_callback.Run(); +} + void BluetoothAdapterMac::RemovePairingDelegateInternal( BluetoothDevice::PairingDelegate* pairing_delegate) { }
diff --git a/device/bluetooth/bluetooth_adapter_unittest.cc b/device/bluetooth/bluetooth_adapter_unittest.cc index 5dd10b1..81e2dcb 100644 --- a/device/bluetooth/bluetooth_adapter_unittest.cc +++ b/device/bluetooth/bluetooth_adapter_unittest.cc
@@ -2,9 +2,11 @@ // 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/memory/ref_counted.h" #include "device/bluetooth/bluetooth_adapter.h" #include "device/bluetooth/bluetooth_device.h" +#include "device/bluetooth/bluetooth_discovery_session.h" #include "testing/gtest/include/gtest/gtest.h" using device::BluetoothAdapter; @@ -49,9 +51,15 @@ void DeleteOnCorrectThread() const override { delete this; } + void StartDiscoverySessionWithFilter( + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter, + const DiscoverySessionCallback& callback, + const ErrorCallback& error_callback) override { + OnStartDiscoverySession(discovery_filter.Pass(), callback); + } + void StartDiscoverySession(const DiscoverySessionCallback& callback, const ErrorCallback& error_callback) override {} - void CreateRfcommService( const BluetoothUUID& uuid, const ServiceOptions& options, @@ -69,15 +77,42 @@ const AcquiredCallback& callback, const BluetoothAudioSink::ErrorCallback& error_callback) override {} + void TestErrorCallback() {} + + ScopedVector<BluetoothDiscoverySession> discovery_sessions_; + + void TestOnStartDiscoverySession( + scoped_ptr<device::BluetoothDiscoverySession> discovery_session) { + discovery_sessions_.push_back(discovery_session.Pass()); + } + + void CleanupSessions() { discovery_sessions_.clear(); } + + void InjectFilteredSession( + scoped_ptr<device::BluetoothDiscoveryFilter> discovery_filter) { + StartDiscoverySessionWithFilter( + discovery_filter.Pass(), + base::Bind(&TestBluetoothAdapter::TestOnStartDiscoverySession, + base::Unretained(this)), + base::Bind(&TestBluetoothAdapter::TestErrorCallback, + base::Unretained(this))); + } + protected: ~TestBluetoothAdapter() override {} - void AddDiscoverySession(const base::Closure& callback, + void AddDiscoverySession(BluetoothDiscoveryFilter* discovery_filter, + const base::Closure& callback, const ErrorCallback& error_callback) override {} - void RemoveDiscoverySession(const base::Closure& callback, + void RemoveDiscoverySession(BluetoothDiscoveryFilter* discovery_filter, + const base::Closure& callback, const ErrorCallback& error_callback) override {} + void SetDiscoveryFilter(scoped_ptr<BluetoothDiscoveryFilter> discovery_filter, + const base::Closure& callback, + const ErrorCallback& error_callback) override {} + void RemovePairingDelegateInternal( BluetoothDevice::PairingDelegate* pairing_delegate) override {} }; @@ -162,4 +197,202 @@ EXPECT_TRUE(adapter->DefaultPairingDelegate() == NULL); } +TEST(BluetoothAdapterTest, GetMergedDiscoveryFilterEmpty) { + scoped_refptr<BluetoothAdapter> adapter = new TestBluetoothAdapter(); + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter; + + discovery_filter = adapter->GetMergedDiscoveryFilter(); + EXPECT_TRUE(discovery_filter.get() == nullptr); + + discovery_filter = adapter->GetMergedDiscoveryFilterMasked(nullptr); + EXPECT_TRUE(discovery_filter.get() == nullptr); +} + +TEST(BluetoothAdapterTest, GetMergedDiscoveryFilterRegular) { + scoped_refptr<TestBluetoothAdapter> adapter = new TestBluetoothAdapter(); + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter; + + // make sure adapter have one session wihout filtering. + adapter->InjectFilteredSession(discovery_filter.Pass()); + + // having one reglar session should result in no filter + scoped_ptr<BluetoothDiscoveryFilter> resulting_filter = + adapter->GetMergedDiscoveryFilter(); + EXPECT_TRUE(resulting_filter.get() == nullptr); + + // omiting no filter when having one reglar session should result in no filter + resulting_filter = adapter->GetMergedDiscoveryFilterMasked(nullptr); + EXPECT_TRUE(resulting_filter.get() == nullptr); + + adapter->CleanupSessions(); +} + +TEST(BluetoothAdapterTest, GetMergedDiscoveryFilterRssi) { + scoped_refptr<TestBluetoothAdapter> adapter = new TestBluetoothAdapter(); + int16_t resulting_rssi; + uint16_t resulting_pathloss; + scoped_ptr<BluetoothDiscoveryFilter> resulting_filter; + + BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df->SetRSSI(-30); + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter(df); + + BluetoothDiscoveryFilter* df2 = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df2->SetRSSI(-65); + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter2(df2); + + // make sure adapter have one session wihout filtering. + adapter->InjectFilteredSession(discovery_filter.Pass()); + + // DO_NOTHING should have no impact + resulting_filter = adapter->GetMergedDiscoveryFilter(); + resulting_filter->GetRSSI(&resulting_rssi); + EXPECT_EQ(-30, resulting_rssi); + + // should not use df2 at all, as it's not associated with adapter yet + resulting_filter = adapter->GetMergedDiscoveryFilterMasked(df2); + resulting_filter->GetRSSI(&resulting_rssi); + EXPECT_EQ(-30, resulting_rssi); + + adapter->InjectFilteredSession(discovery_filter2.Pass()); + + // result of merging two rssi values should be lower one + resulting_filter = adapter->GetMergedDiscoveryFilter(); + resulting_filter->GetRSSI(&resulting_rssi); + EXPECT_EQ(-65, resulting_rssi); + + // ommit bigger value, result should stay same + resulting_filter = adapter->GetMergedDiscoveryFilterMasked(df); + resulting_filter->GetRSSI(&resulting_rssi); + EXPECT_EQ(-65, resulting_rssi); + + // ommit lower value, result should change + resulting_filter = adapter->GetMergedDiscoveryFilterMasked(df2); + resulting_filter->GetRSSI(&resulting_rssi); + EXPECT_EQ(-30, resulting_rssi); + + BluetoothDiscoveryFilter* df3 = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df3->SetPathloss(60); + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter3(df3); + + // when rssi and pathloss are merged, both should be cleared, becuase there is + // no way to tell which filter will be more generic + adapter->InjectFilteredSession(discovery_filter3.Pass()); + resulting_filter = adapter->GetMergedDiscoveryFilter(); + EXPECT_FALSE(resulting_filter->GetRSSI(&resulting_rssi)); + EXPECT_FALSE(resulting_filter->GetPathloss(&resulting_pathloss)); + + adapter->CleanupSessions(); +} + +TEST(BluetoothAdapterTest, GetMergedDiscoveryFilterTransport) { + scoped_refptr<TestBluetoothAdapter> adapter = new TestBluetoothAdapter(); + scoped_ptr<BluetoothDiscoveryFilter> resulting_filter; + + BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_CLASSIC); + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter(df); + + BluetoothDiscoveryFilter* df2 = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter2(df2); + + adapter->InjectFilteredSession(discovery_filter.Pass()); + + // Just one filter, make sure transport was properly rewritten + resulting_filter = adapter->GetMergedDiscoveryFilter(); + EXPECT_EQ(BluetoothDiscoveryFilter::Transport::TRANSPORT_CLASSIC, + resulting_filter->GetTransport()); + + adapter->InjectFilteredSession(discovery_filter2.Pass()); + + // Two filters, should have OR of both transport's + resulting_filter = adapter->GetMergedDiscoveryFilter(); + EXPECT_EQ(BluetoothDiscoveryFilter::Transport::TRANSPORT_DUAL, + resulting_filter->GetTransport()); + + // When 1st filter is masked, 2nd filter transport should be returned. + resulting_filter = adapter->GetMergedDiscoveryFilterMasked(df); + EXPECT_EQ(BluetoothDiscoveryFilter::Transport::TRANSPORT_LE, + resulting_filter->GetTransport()); + + // When 2nd filter is masked, 1st filter transport should be returned. + resulting_filter = adapter->GetMergedDiscoveryFilterMasked(df2); + EXPECT_EQ(BluetoothDiscoveryFilter::Transport::TRANSPORT_CLASSIC, + resulting_filter->GetTransport()); + + BluetoothDiscoveryFilter* df3 = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df3->CopyFrom(BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_DUAL)); + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter3(df3); + + // Merging empty filter in should result in empty filter + adapter->InjectFilteredSession(discovery_filter3.Pass()); + resulting_filter = adapter->GetMergedDiscoveryFilter(); + EXPECT_TRUE(resulting_filter->IsDefault()); + + adapter->CleanupSessions(); +} + +TEST(BluetoothAdapterTest, GetMergedDiscoveryFilterAllFields) { + scoped_refptr<TestBluetoothAdapter> adapter = new TestBluetoothAdapter(); + int16_t resulting_rssi; + std::set<device::BluetoothUUID> resulting_uuids; + + BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df->SetRSSI(-60); + df->AddUUID(device::BluetoothUUID("1000")); + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter(df); + + BluetoothDiscoveryFilter* df2 = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df2->SetRSSI(-85); + df2->SetTransport(BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df2->AddUUID(device::BluetoothUUID("1020")); + df2->AddUUID(device::BluetoothUUID("1001")); + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter2(df2); + + BluetoothDiscoveryFilter* df3 = new BluetoothDiscoveryFilter( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df3->SetRSSI(-65); + df3->SetTransport(BluetoothDiscoveryFilter::Transport::TRANSPORT_CLASSIC); + df3->AddUUID(device::BluetoothUUID("1020")); + df3->AddUUID(device::BluetoothUUID("1003")); + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter3(df3); + + // make sure adapter have one session wihout filtering. + adapter->InjectFilteredSession(discovery_filter.Pass()); + adapter->InjectFilteredSession(discovery_filter2.Pass()); + adapter->InjectFilteredSession(discovery_filter3.Pass()); + + scoped_ptr<BluetoothDiscoveryFilter> resulting_filter = + adapter->GetMergedDiscoveryFilter(); + resulting_filter->GetRSSI(&resulting_rssi); + resulting_filter->GetUUIDs(resulting_uuids); + EXPECT_TRUE(resulting_filter->GetTransport()); + EXPECT_EQ(BluetoothDiscoveryFilter::Transport::TRANSPORT_DUAL, + resulting_filter->GetTransport()); + EXPECT_EQ(-85, resulting_rssi); + EXPECT_EQ(4UL, resulting_uuids.size()); + EXPECT_TRUE(resulting_uuids.find(device::BluetoothUUID("1000")) != + resulting_uuids.end()); + EXPECT_TRUE(resulting_uuids.find(device::BluetoothUUID("1001")) != + resulting_uuids.end()); + EXPECT_TRUE(resulting_uuids.find(device::BluetoothUUID("1003")) != + resulting_uuids.end()); + EXPECT_TRUE(resulting_uuids.find(device::BluetoothUUID("1020")) != + resulting_uuids.end()); + + resulting_filter = adapter->GetMergedDiscoveryFilterMasked(df); + EXPECT_EQ(BluetoothDiscoveryFilter::Transport::TRANSPORT_DUAL, + resulting_filter->GetTransport()); + + adapter->CleanupSessions(); +} + } // namespace device
diff --git a/device/bluetooth/bluetooth_adapter_win.cc b/device/bluetooth/bluetooth_adapter_win.cc index fb28d7cd..a9fc20034 100644 --- a/device/bluetooth/bluetooth_adapter_win.cc +++ b/device/bluetooth/bluetooth_adapter_win.cc
@@ -300,6 +300,7 @@ // If the method is called when |discovery_status_| is DISCOVERY_STOPPING, // starting again is handled by BluetoothAdapterWin::DiscoveryStopped(). void BluetoothAdapterWin::AddDiscoverySession( + BluetoothDiscoveryFilter* discovery_filter, const base::Closure& callback, const ErrorCallback& error_callback) { if (discovery_status_ == DISCOVERING) { @@ -313,6 +314,7 @@ } void BluetoothAdapterWin::RemoveDiscoverySession( + BluetoothDiscoveryFilter* discovery_filter, const base::Closure& callback, const ErrorCallback& error_callback) { if (discovery_status_ == NOT_DISCOVERING) { @@ -323,6 +325,14 @@ MaybePostStopDiscoveryTask(); } +void BluetoothAdapterWin::SetDiscoveryFilter( + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter, + const base::Closure& callback, + const ErrorCallback& error_callback) { + NOTIMPLEMENTED(); + error_callback.Run(); +} + void BluetoothAdapterWin::Init() { ui_task_runner_ = base::ThreadTaskRunnerHandle::Get(); socket_thread_ = BluetoothSocketThread::Get();
diff --git a/device/bluetooth/bluetooth_adapter_win.h b/device/bluetooth/bluetooth_adapter_win.h index 72280ee8..2b086a2f 100644 --- a/device/bluetooth/bluetooth_adapter_win.h +++ b/device/bluetooth/bluetooth_adapter_win.h
@@ -18,6 +18,7 @@ #include "base/threading/thread_checker.h" #include "device/bluetooth/bluetooth_adapter.h" #include "device/bluetooth/bluetooth_audio_sink.h" +#include "device/bluetooth/bluetooth_discovery_session.h" #include "device/bluetooth/bluetooth_export.h" #include "device/bluetooth/bluetooth_task_manager_win.h" @@ -112,9 +113,15 @@ // BluetoothAdapter: void DeleteOnCorrectThread() const override; virtual void AddDiscoverySession( + BluetoothDiscoveryFilter* discovery_filter, const base::Closure& callback, const ErrorCallback& error_callback) override; virtual void RemoveDiscoverySession( + BluetoothDiscoveryFilter* discovery_filter, + const base::Closure& callback, + const ErrorCallback& error_callback) override; + virtual void SetDiscoveryFilter( + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter, const base::Closure& callback, const ErrorCallback& error_callback) override;
diff --git a/device/bluetooth/bluetooth_adapter_win_unittest.cc b/device/bluetooth/bluetooth_adapter_win_unittest.cc index 4a7abd7..670a03dc2 100644 --- a/device/bluetooth/bluetooth_adapter_win_unittest.cc +++ b/device/bluetooth/bluetooth_adapter_win_unittest.cc
@@ -154,13 +154,13 @@ void CallAddDiscoverySession( const base::Closure& callback, const BluetoothAdapter::ErrorCallback& error_callback) { - adapter_win_->AddDiscoverySession(callback, error_callback); + adapter_win_->AddDiscoverySession(nullptr, callback, error_callback); } void CallRemoveDiscoverySession( const base::Closure& callback, const BluetoothAdapter::ErrorCallback& error_callback) { - adapter_win_->RemoveDiscoverySession(callback, error_callback); + adapter_win_->RemoveDiscoverySession(nullptr, callback, error_callback); } protected:
diff --git a/device/bluetooth/bluetooth_chromeos_unittest.cc b/device/bluetooth/bluetooth_chromeos_unittest.cc index da03501..535e047 100644 --- a/device/bluetooth/bluetooth_chromeos_unittest.cc +++ b/device/bluetooth/bluetooth_chromeos_unittest.cc
@@ -3251,11 +3251,13 @@ EXPECT_EQ(0, callback_count_) << "OnPropertyChangeCompleted error"; EXPECT_EQ(1, error_callback_count_--) << "OnPropertyChangeCompleted error"; - adapter_chrome_os->AddDiscoverySession(GetCallback(), GetErrorCallback()); + adapter_chrome_os->AddDiscoverySession(nullptr, GetCallback(), + GetErrorCallback()); EXPECT_EQ(0, callback_count_) << "AddDiscoverySession error"; EXPECT_EQ(1, error_callback_count_--) << "AddDiscoverySession error"; - adapter_chrome_os->RemoveDiscoverySession(GetCallback(), GetErrorCallback()); + adapter_chrome_os->RemoveDiscoverySession(nullptr, GetCallback(), + GetErrorCallback()); EXPECT_EQ(0, callback_count_) << "RemoveDiscoverySession error"; EXPECT_EQ(1, error_callback_count_--) << "RemoveDiscoverySession error"; @@ -3321,7 +3323,8 @@ static_cast<BluetoothAdapterChromeOS*>(adapter_.get()); for (int i = 0; i < kNumberOfDiscoverySessions; i++) { - adapter_chrome_os->AddDiscoverySession(GetCallback(), GetErrorCallback()); + adapter_chrome_os->AddDiscoverySession(nullptr, GetCallback(), + GetErrorCallback()); } adapter_->Shutdown(); adapter_chrome_os->OnStartDiscovery(GetCallback(), GetErrorCallback()); @@ -3338,7 +3341,8 @@ static_cast<BluetoothAdapterChromeOS*>(adapter_.get()); for (int i = 0; i < kNumberOfDiscoverySessions; i++) { - adapter_chrome_os->AddDiscoverySession(GetCallback(), GetErrorCallback()); + adapter_chrome_os->AddDiscoverySession(nullptr, GetCallback(), + GetErrorCallback()); } adapter_->Shutdown(); adapter_chrome_os->OnStartDiscoveryError(GetCallback(), GetErrorCallback(), @@ -3357,14 +3361,17 @@ // In order to queue up discovery sessions before an OnStopDiscovery call // RemoveDiscoverySession must be called, so Add, Start, and Remove: - adapter_chrome_os->AddDiscoverySession(GetCallback(), GetErrorCallback()); + adapter_chrome_os->AddDiscoverySession(nullptr, GetCallback(), + GetErrorCallback()); adapter_chrome_os->OnStartDiscovery(GetCallback(), GetErrorCallback()); - adapter_chrome_os->RemoveDiscoverySession(GetCallback(), GetErrorCallback()); + adapter_chrome_os->RemoveDiscoverySession(nullptr, GetCallback(), + GetErrorCallback()); callback_count_ = 0; error_callback_count_ = 0; // Can now queue discovery sessions while waiting for OnStopDiscovery. for (int i = 0; i < kNumberOfDiscoverySessions; i++) { - adapter_chrome_os->AddDiscoverySession(GetCallback(), GetErrorCallback()); + adapter_chrome_os->AddDiscoverySession(nullptr, GetCallback(), + GetErrorCallback()); } adapter_->Shutdown(); adapter_chrome_os->OnStopDiscovery(GetCallback()); @@ -3384,14 +3391,17 @@ // In order to queue up discovery sessions before an OnStopDiscoveryError call // RemoveDiscoverySession must be called, so Add, Start, and Remove: - adapter_chrome_os->AddDiscoverySession(GetCallback(), GetErrorCallback()); + adapter_chrome_os->AddDiscoverySession(nullptr, GetCallback(), + GetErrorCallback()); adapter_chrome_os->OnStartDiscovery(GetCallback(), GetErrorCallback()); - adapter_chrome_os->RemoveDiscoverySession(GetCallback(), GetErrorCallback()); + adapter_chrome_os->RemoveDiscoverySession(nullptr, GetCallback(), + GetErrorCallback()); callback_count_ = 0; error_callback_count_ = 0; // Can now queue discovery sessions while waiting for OnStopDiscoveryError. for (int i = 0; i < kNumberOfDiscoverySessions; i++) { - adapter_chrome_os->AddDiscoverySession(GetCallback(), GetErrorCallback()); + adapter_chrome_os->AddDiscoverySession(nullptr, GetCallback(), + GetErrorCallback()); } adapter_->Shutdown(); adapter_chrome_os->OnStopDiscoveryError(GetErrorCallback(), "", "");
diff --git a/device/bluetooth/bluetooth_discovery_filter_unittest.cc b/device/bluetooth/bluetooth_discovery_filter_unittest.cc new file mode 100644 index 0000000..ea7a04f --- /dev/null +++ b/device/bluetooth/bluetooth_discovery_filter_unittest.cc
@@ -0,0 +1,181 @@ +// 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 "device/bluetooth/bluetooth_discovery_session.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +const device::BluetoothUUID uuid1003("1003"); +const device::BluetoothUUID uuid1004("1004"); +const device::BluetoothUUID uuid1020("1020"); + +} // namespace + +namespace device { + +TEST(BluetoothDiscoveryFilterTest, Equal) { + BluetoothDiscoveryFilter df1( + BluetoothDiscoveryFilter::Transport::TRANSPORT_CLASSIC); + df1.SetRSSI(-65); + df1.AddUUID(uuid1020); + df1.AddUUID(uuid1003); + + BluetoothDiscoveryFilter df2( + BluetoothDiscoveryFilter::Transport::TRANSPORT_CLASSIC); + df2.SetRSSI(-65); + df2.AddUUID(uuid1020); + df2.AddUUID(uuid1004); + + // uuids are not same, so should fail + ASSERT_FALSE(df1.Equals(df2)); + + // make filters equal + df1.AddUUID(uuid1004); + df2.AddUUID(uuid1003); + ASSERT_TRUE(df1.Equals(df2)); + + // now transport don't match + df1.SetTransport(BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + ASSERT_FALSE(df1.Equals(df2)); + + // now everything is back matching + df1.SetTransport(BluetoothDiscoveryFilter::Transport::TRANSPORT_CLASSIC); + ASSERT_TRUE(df1.Equals(df2)); + + // now rssi don't match + df1.SetRSSI(-30); + ASSERT_FALSE(df1.Equals(df2)); + + BluetoothDiscoveryFilter df3( + BluetoothDiscoveryFilter::Transport::TRANSPORT_CLASSIC); + df3.SetPathloss(45); + df3.AddUUID(uuid1020); + df3.AddUUID(uuid1003); + df3.AddUUID(uuid1004); + + // Having Pathloss and RSSI set in two different filter makes them unequal. + ASSERT_FALSE(df1.Equals(df3)); +} + +TEST(BluetoothDiscoveryFilterTest, CopyFrom) { + BluetoothDiscoveryFilter df1( + BluetoothDiscoveryFilter::Transport::TRANSPORT_CLASSIC); + df1.SetRSSI(-65); + df1.AddUUID(uuid1020); + df1.AddUUID(uuid1003); + + BluetoothDiscoveryFilter df2( + BluetoothDiscoveryFilter::Transport::TRANSPORT_CLASSIC); + + df2.CopyFrom(df1); + + int16_t out_rssi; + std::set<device::BluetoothUUID> out_uuids; + + // make sure all properties were copied + df2.GetRSSI(&out_rssi); + EXPECT_EQ(-65, out_rssi); + + EXPECT_EQ(BluetoothDiscoveryFilter::Transport::TRANSPORT_CLASSIC, + df2.GetTransport()); + + df2.GetUUIDs(out_uuids); + EXPECT_TRUE(out_uuids.find(uuid1020) != out_uuids.end()); + EXPECT_TRUE(out_uuids.find(uuid1003) != out_uuids.end()); +} + +TEST(BluetoothDiscoveryFilterTest, MergeUUIDs) { + BluetoothDiscoveryFilter df1( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df1.AddUUID(uuid1020); + df1.AddUUID(uuid1003); + + BluetoothDiscoveryFilter df2( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df2.AddUUID(uuid1020); + df2.AddUUID(uuid1004); + + scoped_ptr<BluetoothDiscoveryFilter> df3 = + BluetoothDiscoveryFilter::Merge(&df1, &df2); + + // df3 should contain all uuids from df1 and df2 + std::set<device::BluetoothUUID> out_uuids; + df3->GetUUIDs(out_uuids); + EXPECT_TRUE(out_uuids.find(uuid1020) != out_uuids.end()); + EXPECT_TRUE(out_uuids.find(uuid1003) != out_uuids.end()); + EXPECT_TRUE(out_uuids.find(uuid1004) != out_uuids.end()); + + // Merging with empty filter would return empty filter + df3 = BluetoothDiscoveryFilter::Merge(&df1, nullptr); + df3->GetUUIDs(out_uuids); + EXPECT_EQ(0UL, out_uuids.size()); + EXPECT_TRUE(df3->IsDefault()); +} + +TEST(BluetoothDiscoveryFilterTest, MergeProximity) { + BluetoothDiscoveryFilter df1( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df1.SetRSSI(-50); + + BluetoothDiscoveryFilter df2( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df2.SetRSSI(-70); + + BluetoothDiscoveryFilter df3( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df3.SetPathloss(70); + + BluetoothDiscoveryFilter df4( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + df4.SetPathloss(20); + + scoped_ptr<BluetoothDiscoveryFilter> result = + BluetoothDiscoveryFilter::Merge(&df1, &df2); + + int16_t out_rssi; + // Merging RSSI should return smaller of both values + EXPECT_TRUE(result->GetRSSI(&out_rssi)); + EXPECT_EQ(-70, out_rssi); + + uint16_t out_pathloss; + // Merging RSSI with Pathloss should clear proximity + result = BluetoothDiscoveryFilter::Merge(&df1, &df3); + EXPECT_FALSE(result->GetRSSI(&out_rssi)); + EXPECT_FALSE(result->GetPathloss(&out_pathloss)); + + // Merging Pathloss should return bigger of both values + result = BluetoothDiscoveryFilter::Merge(&df3, &df4); + EXPECT_TRUE(result->GetPathloss(&out_pathloss)); + EXPECT_EQ(70, out_pathloss); +} + +TEST(BluetoothDiscoveryFilterTest, MergeTransport) { + BluetoothDiscoveryFilter df1( + BluetoothDiscoveryFilter::Transport::TRANSPORT_CLASSIC); + + BluetoothDiscoveryFilter df2( + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); + + BluetoothDiscoveryFilter df3( + BluetoothDiscoveryFilter::Transport::TRANSPORT_DUAL); + + scoped_ptr<BluetoothDiscoveryFilter> result = + BluetoothDiscoveryFilter::Merge(&df1, &df2); + + // Merging LE and CLASSIC should result in both being set + EXPECT_EQ(BluetoothDiscoveryFilter::Transport::TRANSPORT_DUAL, + result->GetTransport()); + + result = BluetoothDiscoveryFilter::Merge(&df1, &df3); + EXPECT_EQ(BluetoothDiscoveryFilter::Transport::TRANSPORT_DUAL, + result->GetTransport()); + + // Merging with null should alway result with empty filter. + result = BluetoothDiscoveryFilter::Merge(&df1, nullptr); + EXPECT_TRUE(result->IsDefault()); +} + +} // namespace device
diff --git a/device/bluetooth/bluetooth_discovery_session.cc b/device/bluetooth/bluetooth_discovery_session.cc index bfcc59f..e30f86cc 100644 --- a/device/bluetooth/bluetooth_discovery_session.cc +++ b/device/bluetooth/bluetooth_discovery_session.cc
@@ -9,9 +9,180 @@ namespace device { +BluetoothDiscoveryFilter::BluetoothDiscoveryFilter(TransportMask transport) { + SetTransport(transport); +} + +BluetoothDiscoveryFilter::~BluetoothDiscoveryFilter() { +} + +bool BluetoothDiscoveryFilter::GetRSSI(int16_t* out_rssi) const { + DCHECK(out_rssi); + if (!rssi_.get()) + return false; + + *out_rssi = *rssi_; + return true; +} + +void BluetoothDiscoveryFilter::SetRSSI(int16_t rssi) { + if (!rssi_.get()) + rssi_.reset(new int16_t()); + + *rssi_ = rssi; +} + +bool BluetoothDiscoveryFilter::GetPathloss(uint16_t* out_pathloss) const { + DCHECK(out_pathloss); + if (!pathloss_.get()) + return false; + + *out_pathloss = *pathloss_; + return true; +} + +void BluetoothDiscoveryFilter::SetPathloss(uint16_t pathloss) { + if (!pathloss_.get()) + pathloss_.reset(new uint16_t()); + + *pathloss_ = pathloss; +} + +BluetoothDiscoveryFilter::TransportMask BluetoothDiscoveryFilter::GetTransport() + const { + return transport_; +} + +void BluetoothDiscoveryFilter::SetTransport(TransportMask transport) { + DCHECK(transport > 0 && transport < 4); + transport_ = transport; +} + +void BluetoothDiscoveryFilter::GetUUIDs( + std::set<device::BluetoothUUID>& out_uuids) const { + out_uuids.clear(); + + for (auto& uuid : uuids_) + out_uuids.insert(*uuid); +} + +void BluetoothDiscoveryFilter::AddUUID(const device::BluetoothUUID& uuid) { + DCHECK(uuid.IsValid()); + for (auto& uuid_it : uuids_) { + if (*uuid_it == uuid) + return; + } + + uuids_.push_back(new device::BluetoothUUID(uuid)); +} + +void BluetoothDiscoveryFilter::CopyFrom( + const BluetoothDiscoveryFilter& filter) { + transport_ = filter.transport_; + + if (filter.uuids_.size()) { + for (auto& uuid : filter.uuids_) + AddUUID(*uuid); + } else + uuids_.clear(); + + if (filter.rssi_.get()) { + SetRSSI(*filter.rssi_); + } else + rssi_.reset(); + + if (filter.pathloss_.get()) { + SetPathloss(*filter.pathloss_); + } else + pathloss_.reset(); +} + +scoped_ptr<device::BluetoothDiscoveryFilter> BluetoothDiscoveryFilter::Merge( + const device::BluetoothDiscoveryFilter* filter_a, + const device::BluetoothDiscoveryFilter* filter_b) { + scoped_ptr<BluetoothDiscoveryFilter> result; + + if (!filter_a && !filter_b) { + return result; + } + + result.reset(new BluetoothDiscoveryFilter(Transport::TRANSPORT_DUAL)); + + if (!filter_a || !filter_b || filter_a->IsDefault() || + filter_b->IsDefault()) { + return result; + } + + // both filters are not empty, so they must have transport set. + result->SetTransport(filter_a->transport_ | filter_b->transport_); + + // if both filters have uuids, them merge them. Otherwise uuids filter should + // be left empty + if (filter_a->uuids_.size() && filter_b->uuids_.size()) { + std::set<device::BluetoothUUID> uuids; + filter_a->GetUUIDs(uuids); + for (auto& uuid : uuids) + result->AddUUID(uuid); + + filter_b->GetUUIDs(uuids); + for (auto& uuid : uuids) + result->AddUUID(uuid); + } + + if ((filter_a->rssi_.get() && filter_b->pathloss_.get()) || + (filter_a->pathloss_.get() && filter_b->rssi_.get())) { + // if both rssi and pathloss filtering is enabled in two different + // filters, we can't tell which filter is more generic, and we don't set + // proximity filtering on merged filter. + return result; + } + + if (filter_a->rssi_.get() && filter_b->rssi_.get()) { + result->SetRSSI(std::min(*filter_a->rssi_, *filter_b->rssi_)); + } else if (filter_a->pathloss_.get() && filter_b->pathloss_.get()) { + result->SetPathloss(std::max(*filter_a->pathloss_, *filter_b->pathloss_)); + } + + return result; +} + +bool BluetoothDiscoveryFilter::Equals( + const BluetoothDiscoveryFilter& other) const { + if (((!!rssi_.get()) != (!!other.rssi_.get())) || + (rssi_.get() && other.rssi_.get() && *rssi_ != *other.rssi_)) { + return false; + } + + if (((!!pathloss_.get()) != (!!other.pathloss_.get())) || + (pathloss_.get() && other.pathloss_.get() && + *pathloss_ != *other.pathloss_)) { + return false; + } + + if (transport_ != other.transport_) + return false; + + std::set<device::BluetoothUUID> uuids_a, uuids_b; + GetUUIDs(uuids_a); + other.GetUUIDs(uuids_b); + if (uuids_a != uuids_b) + return false; + + return true; +} + +bool BluetoothDiscoveryFilter::IsDefault() const { + return !(rssi_.get() || pathloss_.get() || uuids_.size() || + transport_ != Transport::TRANSPORT_DUAL); +} + BluetoothDiscoverySession::BluetoothDiscoverySession( - scoped_refptr<BluetoothAdapter> adapter) - : active_(true), adapter_(adapter), weak_ptr_factory_(this) { + scoped_refptr<BluetoothAdapter> adapter, + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter) + : active_(true), + adapter_(adapter), + discovery_filter_(discovery_filter.release()), + weak_ptr_factory_(this) { DCHECK(adapter_.get()); } @@ -36,14 +207,15 @@ } VLOG(1) << "Stopping device discovery session."; adapter_->RemoveDiscoverySession( + discovery_filter_.get(), base::Bind(&BluetoothDiscoverySession::OnStop, - weak_ptr_factory_.GetWeakPtr(), - callback), + weak_ptr_factory_.GetWeakPtr(), callback), error_callback); } void BluetoothDiscoverySession::OnStop(const base::Closure& callback) { MarkAsInactive(); + discovery_filter_.reset(); callback.Run(); } @@ -54,4 +226,18 @@ adapter_->DiscoverySessionBecameInactive(this); } +void BluetoothDiscoverySession::SetDiscoveryFilter( + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter, + const base::Closure& callback, + const ErrorCallback& error_callback) { + discovery_filter_.reset(discovery_filter.release()); + adapter_->SetDiscoveryFilter(adapter_->GetMergedDiscoveryFilter().Pass(), + callback, error_callback); +} + +const BluetoothDiscoveryFilter* BluetoothDiscoverySession::GetDiscoveryFilter() + const { + return discovery_filter_.get(); +} + } // namespace device
diff --git a/device/bluetooth/bluetooth_discovery_session.h b/device/bluetooth/bluetooth_discovery_session.h index 2dae0de..d50bf9cd 100644 --- a/device/bluetooth/bluetooth_discovery_session.h +++ b/device/bluetooth/bluetooth_discovery_session.h
@@ -8,11 +8,67 @@ #include "base/callback.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" +#include "device/bluetooth/bluetooth_adapter.h" #include "device/bluetooth/bluetooth_export.h" namespace device { -class BluetoothAdapter; +// used to keep discovery filter that might be Used to limit reported devices. +class DEVICE_BLUETOOTH_EXPORT BluetoothDiscoveryFilter { + public: + // Possible transports to use for scan filter. + enum Transport { + TRANSPORT_CLASSIC = 0x01, + TRANSPORT_LE = 0x02, + TRANSPORT_DUAL = (TRANSPORT_CLASSIC | TRANSPORT_LE) + }; + using TransportMask = uint8_t; + + BluetoothDiscoveryFilter(TransportMask transport); + ~BluetoothDiscoveryFilter(); + + // These getters return true when given field is set in filter, and copy this + // value to |out_*| parameter. If value is not set, returns false. + // Thes setters assign given value to proper filter field. + bool GetRSSI(int16_t* out_rssi) const; + void SetRSSI(int16_t rssi); + bool GetPathloss(uint16_t* out_pathloss) const; + void SetPathloss(uint16_t pathloss); + + // Return and set transport field of this filter. + TransportMask GetTransport() const; + void SetTransport(TransportMask transport); + + // Make |out_uuids| represent all uuids assigned to this filter. + void GetUUIDs(std::set<device::BluetoothUUID>& out_uuids) const; + + // Add UUID to internal UUIDs filter. If UUIDs filter doesn't exist, it will + // be created. + void AddUUID(const device::BluetoothUUID& uuid); + + // Copy content of |filter| and assigns it to this filter. + void CopyFrom(const BluetoothDiscoveryFilter& filter); + + // Check if two filters are equal. + bool Equals(const BluetoothDiscoveryFilter& filter) const; + + // Returns true if all fields in filter are empty + bool IsDefault() const; + + // Returns result of merging two filters together. If at least one of the + // filters is NULL this will return an empty filter + static scoped_ptr<device::BluetoothDiscoveryFilter> Merge( + const device::BluetoothDiscoveryFilter* filter_a, + const device::BluetoothDiscoveryFilter* filter_b); + + private: + scoped_ptr<int16_t> rssi_; + scoped_ptr<uint16_t> pathloss_; + TransportMask transport_; + ScopedVector<device::BluetoothUUID> uuids_; + + DISALLOW_COPY_AND_ASSIGN(BluetoothDiscoveryFilter); +}; // BluetoothDiscoverySession represents a current active or inactive device // discovery session. Instances of this class are obtained by calling @@ -58,8 +114,17 @@ virtual void Stop(const base::Closure& callback, const ErrorCallback& error_callback); + virtual void SetDiscoveryFilter( + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter, + const base::Closure& callback, + const ErrorCallback& error_callback); + + virtual const BluetoothDiscoveryFilter* GetDiscoveryFilter() const; + protected: - explicit BluetoothDiscoverySession(scoped_refptr<BluetoothAdapter> adapter); + explicit BluetoothDiscoverySession( + scoped_refptr<BluetoothAdapter> adapter, + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter); private: friend class BluetoothAdapter; @@ -78,6 +143,9 @@ // The adapter that created this instance. scoped_refptr<BluetoothAdapter> adapter_; + // Filter assigned to this session, if any + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter_; + // Note: This should remain the last member so it'll be destroyed and // invalidate its weak pointers before any other members are destroyed. base::WeakPtrFactory<BluetoothDiscoverySession> weak_ptr_factory_;
diff --git a/device/bluetooth/test/mock_bluetooth_adapter.cc b/device/bluetooth/test/mock_bluetooth_adapter.cc index 2f797d3..1ee00ee0 100644 --- a/device/bluetooth/test/mock_bluetooth_adapter.cc +++ b/device/bluetooth/test/mock_bluetooth_adapter.cc
@@ -24,11 +24,21 @@ }; void MockBluetoothAdapter::AddDiscoverySession( + BluetoothDiscoveryFilter* discovery_filter, const base::Closure& callback, - const ErrorCallback& error_callback) {} + const ErrorCallback& error_callback) { +} void MockBluetoothAdapter::RemoveDiscoverySession( + BluetoothDiscoveryFilter* discovery_filter, const base::Closure& callback, - const ErrorCallback& error_callback) {} + const ErrorCallback& error_callback) { +} + +void MockBluetoothAdapter::SetDiscoveryFilter( + scoped_ptr<BluetoothDiscoveryFilter> discovery_filter, + const base::Closure& callback, + const ErrorCallback& error_callback) { +} } // namespace device
diff --git a/device/bluetooth/test/mock_bluetooth_adapter.h b/device/bluetooth/test/mock_bluetooth_adapter.h index fd67936..d338256 100644 --- a/device/bluetooth/test/mock_bluetooth_adapter.h +++ b/device/bluetooth/test/mock_bluetooth_adapter.h
@@ -11,6 +11,7 @@ #include "device/bluetooth/bluetooth_adapter.h" #include "device/bluetooth/bluetooth_audio_sink.h" #include "device/bluetooth/bluetooth_device.h" +#include "device/bluetooth/bluetooth_discovery_session.h" #include "testing/gmock/include/gmock/gmock.h" namespace device { @@ -87,10 +88,15 @@ protected: void DeleteOnCorrectThread() const override; - virtual void AddDiscoverySession(const base::Closure& callback, - const ErrorCallback& error_callback); - virtual void RemoveDiscoverySession(const base::Closure& callback, - const ErrorCallback& error_callback); + void AddDiscoverySession(BluetoothDiscoveryFilter* discovery_filter, + const base::Closure& callback, + const ErrorCallback& error_callback) override; + void RemoveDiscoverySession(BluetoothDiscoveryFilter* discovery_filter, + const base::Closure& callback, + const ErrorCallback& error_callback) override; + void SetDiscoveryFilter(scoped_ptr<BluetoothDiscoveryFilter> discovery_filter, + const base::Closure& callback, + const ErrorCallback& error_callback) override; virtual ~MockBluetoothAdapter(); MOCK_METHOD1(RemovePairingDelegateInternal,
diff --git a/device/bluetooth/test/mock_bluetooth_discovery_session.cc b/device/bluetooth/test/mock_bluetooth_discovery_session.cc index 295f9546..1aea85a 100644 --- a/device/bluetooth/test/mock_bluetooth_discovery_session.cc +++ b/device/bluetooth/test/mock_bluetooth_discovery_session.cc
@@ -15,8 +15,10 @@ // test code. MockBluetoothDiscoverySession::MockBluetoothDiscoverySession() : BluetoothDiscoverySession( - scoped_refptr<BluetoothAdapter>( - new testing::NiceMock<MockBluetoothAdapter>())) {} + scoped_refptr<BluetoothAdapter>( + new testing::NiceMock<MockBluetoothAdapter>()), + nullptr) { +} MockBluetoothDiscoverySession::~MockBluetoothDiscoverySession() {} } // namespace device
diff --git a/device/device_tests.gyp b/device/device_tests.gyp index 9bf39ac..8b1545a0 100644 --- a/device/device_tests.gyp +++ b/device/device_tests.gyp
@@ -40,6 +40,7 @@ 'bluetooth/bluetooth_chromeos_unittest.cc', 'bluetooth/bluetooth_device_unittest.cc', 'bluetooth/bluetooth_device_win_unittest.cc', + 'bluetooth/bluetooth_discovery_filter_unittest.cc', 'bluetooth/bluetooth_gatt_chromeos_unittest.cc', 'bluetooth/bluetooth_low_energy_win_unittest.cc', 'bluetooth/bluetooth_service_record_win_unittest.cc',
diff --git a/device/hid/hid_service_mac.cc b/device/hid/hid_service_mac.cc index fb12d96e..081e668 100644 --- a/device/hid/hid_service_mac.cc +++ b/device/hid/hid_service_mac.cc
@@ -142,9 +142,17 @@ base::ScopedCFTypeRef<CFDictionaryRef> matching_dict( IORegistryEntryIDMatching(device_id)); + if (!matching_dict.get()) { + HID_LOG(EVENT) << "Failed to create matching dictionary for ID: " + << device_id; + task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); + return; + } - base::mac::ScopedIOObject<io_service_t> service( - IOServiceGetMatchingService(kIOMasterPortDefault, matching_dict.get())); + // IOServiceGetMatchingService consumes a reference to the matching dictionary + // passed to it. + base::mac::ScopedIOObject<io_service_t> service(IOServiceGetMatchingService( + kIOMasterPortDefault, matching_dict.release())); if (!service.get()) { HID_LOG(EVENT) << "IOService not found for ID: " << device_id; task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr));
diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json index 9907815..2992c79e 100644 --- a/extensions/common/api/_api_features.json +++ b/extensions/common/api/_api_features.json
@@ -223,6 +223,7 @@ "channel": "stable", "contexts": ["webui"], "matches": [ + "chrome://md-settings/*", "chrome://network/*", "chrome://settings/*", "chrome://settings-frame/*"
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc index c61b1889..46abc432 100644 --- a/extensions/renderer/dispatcher.cc +++ b/extensions/renderer/dispatcher.cc
@@ -365,7 +365,8 @@ return; context->DispatchOnUnloadEvent(); - // TODO(kalman): add an invalidation observer interface to ScriptContext. + // TODO(kalman): Make |request_sender| use |context->AddInvalidationObserver|. + // In fact |request_sender_| should really be owned by ScriptContext. request_sender_->InvalidateSource(context); script_context_set_.Remove(context);
diff --git a/extensions/renderer/event_bindings.cc b/extensions/renderer/event_bindings.cc index 8a005aa..472f369 100644 --- a/extensions/renderer/event_bindings.cc +++ b/extensions/renderer/event_bindings.cc
@@ -5,9 +5,6 @@ #include "extensions/renderer/event_bindings.h" #include <map> -#include <set> -#include <string> -#include <vector> #include "base/basictypes.h" #include "base/bind.h" @@ -24,9 +21,7 @@ #include "extensions/common/value_counter.h" #include "extensions/renderer/dispatcher.h" #include "extensions/renderer/extension_helper.h" -#include "extensions/renderer/object_backed_native_handler.h" #include "url/gurl.h" -#include "v8/include/v8.h" namespace extensions { @@ -143,12 +138,10 @@ EventBindings::EventBindings(Dispatcher* dispatcher, ScriptContext* context) : ObjectBackedNativeHandler(context), dispatcher_(dispatcher) { - RouteFunction( - "AttachEvent", - base::Bind(&EventBindings::AttachEvent, base::Unretained(this))); - RouteFunction( - "DetachEvent", - base::Bind(&EventBindings::DetachEvent, base::Unretained(this))); + RouteFunction("AttachEvent", base::Bind(&EventBindings::AttachEventHandler, + base::Unretained(this))); + RouteFunction("DetachEvent", base::Bind(&EventBindings::DetachEventHandler, + base::Unretained(this))); RouteFunction( "AttachFilteredEvent", base::Bind(&EventBindings::AttachFilteredEvent, base::Unretained(this))); @@ -158,21 +151,36 @@ RouteFunction("MatchAgainstEventFilter", base::Bind(&EventBindings::MatchAgainstEventFilter, base::Unretained(this))); + + // It's safe to use base::Unretained here because |context| will always + // outlive us. + context->AddInvalidationObserver( + base::Bind(&EventBindings::OnInvalidated, base::Unretained(this))); } EventBindings::~EventBindings() {} -// Attach an event name to an object. -void EventBindings::AttachEvent( +void EventBindings::AttachEventHandler( const v8::FunctionCallbackInfo<v8::Value>& args) { CHECK_EQ(1, args.Length()); CHECK(args[0]->IsString()); + AttachEvent(*v8::String::Utf8Value(args[0])); +} - std::string event_name = *v8::String::Utf8Value(args[0]); - +void EventBindings::AttachEvent(const std::string& event_name) { + // This method throws an exception if it returns false. if (!dispatcher_->CheckContextAccessToExtensionAPI(event_name, context())) return; + // Record the attachment for this context so that events can be detached when + // the context is destroyed. + // + // Ideally we'd CHECK that it's not already attached, however that's not + // possible because extensions can create and attach events themselves. Very + // silly, but that's the way it is. For an example of this, see + // chrome/test/data/extensions/api_test/events/background.js. + attached_event_names_.insert(event_name); + const std::string& extension_id = context()->GetExtensionID(); if (IncrementEventListenerCount(context(), event_name) == 1) { content::RenderThread::Get()->Send(new ExtensionHostMsg_AddListener( @@ -189,16 +197,20 @@ } } -void EventBindings::DetachEvent( +void EventBindings::DetachEventHandler( const v8::FunctionCallbackInfo<v8::Value>& args) { CHECK_EQ(2, args.Length()); CHECK(args[0]->IsString()); CHECK(args[1]->IsBoolean()); + DetachEvent(*v8::String::Utf8Value(args[0]), args[1]->BooleanValue()); +} - std::string event_name = *v8::String::Utf8Value(args[0]); - bool is_manual = args[1]->BooleanValue(); +void EventBindings::DetachEvent(const std::string& event_name, bool is_manual) { + // See comment in AttachEvent(). + attached_event_names_.erase(event_name); const std::string& extension_id = context()->GetExtensionID(); + if (DecrementEventListenerCount(context(), event_name) == 0) { content::RenderThread::Get()->Send(new ExtensionHostMsg_RemoveListener( extension_id, context()->GetURL(), event_name)); @@ -324,4 +336,15 @@ context()->GetRenderView()->GetRoutingID())); } +void EventBindings::OnInvalidated() { + // Detach all attached events that weren't attached. Iterate over a copy + // because it will be mutated. + std::set<std::string> attached_event_names_safe = attached_event_names_; + for (const std::string& event_name : attached_event_names_safe) { + DetachEvent(event_name, false /* is_manual */); + } + DCHECK(attached_event_names_.empty()) + << "Events cannot be attached during invalidation"; +} + } // namespace extensions
diff --git a/extensions/renderer/event_bindings.h b/extensions/renderer/event_bindings.h index 0f69cd3..f5cfdcf 100644 --- a/extensions/renderer/event_bindings.h +++ b/extensions/renderer/event_bindings.h
@@ -5,6 +5,10 @@ #ifndef EXTENSIONS_RENDERER_EVENT_BINDINGS_H_ #define EXTENSIONS_RENDERER_EVENT_BINDINGS_H_ +#include <set> +#include <string> + +#include "base/macros.h" #include "extensions/renderer/object_backed_native_handler.h" #include "v8/include/v8.h" @@ -14,8 +18,6 @@ namespace extensions { class Dispatcher; -class EventFilter; -class EventFilteringInfo; class EventMatcher; // This class deals with the javascript bindings related to Event objects. @@ -25,16 +27,25 @@ ~EventBindings() override; private: + // JavaScript handler which forwards to AttachEvent(). + // args[0] forwards to |event_name|. + void AttachEventHandler(const v8::FunctionCallbackInfo<v8::Value>& args); + // Attach an event name to an object. // |event_name| The name of the event to attach. - void AttachEvent(const v8::FunctionCallbackInfo<v8::Value>& args); + void AttachEvent(const std::string& event_name); - // Detach an event name from an object. + // JavaScript handler which forwards to DetachEvent(). + // args[0] forwards to |event_name|. + // args[1] forwards to |is_manual|. + void DetachEventHandler(const v8::FunctionCallbackInfo<v8::Value>& args); + + // Detaches an event name from an object. // |event_name| The name of the event to stop listening to. // |is_manual| True if this detach was done by the user via removeListener() // as opposed to automatically during shutdown, in which case we should inform // the browser we are no longer interested in that event. - void DetachEvent(const v8::FunctionCallbackInfo<v8::Value>& args); + void DetachEvent(const std::string& event_name, bool is_manual); // MatcherID AttachFilteredEvent(string event_name, object filter) // |event_name| Name of the event to attach. @@ -51,9 +62,19 @@ void MatchAgainstEventFilter(const v8::FunctionCallbackInfo<v8::Value>& args); - Dispatcher* dispatcher_; scoped_ptr<EventMatcher> ParseEventMatcher( base::DictionaryValue* filter_dict); + + // Called when our context, and therefore us, is invalidated. Run any cleanup. + void OnInvalidated(); + + // The set of attached events. Maintain this so that we can detch them on + // unload. + std::set<std::string> attached_event_names_; + + Dispatcher* dispatcher_; + + DISALLOW_COPY_AND_ASSIGN(EventBindings); }; } // namespace extensions
diff --git a/extensions/renderer/event_unittest.cc b/extensions/renderer/event_unittest.cc index 4144a01..9d3b68f 100644 --- a/extensions/renderer/event_unittest.cc +++ b/extensions/renderer/event_unittest.cc
@@ -18,7 +18,6 @@ env()->RegisterModule(kSchemaUtils, IDR_SCHEMA_UTILS_JS); env()->RegisterModule("uncaught_exception_handler", IDR_UNCAUGHT_EXCEPTION_HANDLER_JS); - env()->RegisterModule("unload_event", IDR_UNLOAD_EVENT_JS); env()->RegisterModule("utils", IDR_UTILS_JS); // Mock out the native handler for event_bindings. These mocks will fail if @@ -92,41 +91,6 @@ env()->module_system()->Require("test"); } -TEST_F(EventUnittest, OnUnloadDetachesAllListeners) { - ModuleSystem::NativesEnabledScope natives_enabled_scope( - env()->module_system()); - env()->RegisterModule( - "test", - "var assert = requireNative('assert');" - "var Event = require('event_bindings').Event;" - "var eventNatives = requireNative('event_natives');" - "var myEvent = new Event('named-event');" - "var cb1 = function() {};" - "var cb2 = function() {};" - "myEvent.addListener(cb1);" - "myEvent.addListener(cb2);" - "require('unload_event').dispatch();" - "assert.AssertFalse(!!eventNatives.attachedListeners['named-event']);"); - env()->module_system()->Require("test"); -} - -TEST_F(EventUnittest, OnUnloadDetachesAllListenersEvenDupes) { - ModuleSystem::NativesEnabledScope natives_enabled_scope( - env()->module_system()); - env()->RegisterModule( - "test", - "var assert = requireNative('assert');" - "var Event = require('event_bindings').Event;" - "var eventNatives = requireNative('event_natives');" - "var myEvent = new Event('named-event');" - "var cb1 = function() {};" - "myEvent.addListener(cb1);" - "myEvent.addListener(cb1);" - "require('unload_event').dispatch();" - "assert.AssertFalse(!!eventNatives.attachedListeners['named-event']);"); - env()->module_system()->Require("test"); -} - TEST_F(EventUnittest, EventsThatSupportRulesMustHaveAName) { ModuleSystem::NativesEnabledScope natives_enabled_scope( env()->module_system());
diff --git a/extensions/renderer/module_system.cc b/extensions/renderer/module_system.cc index 6194b8e..6a120749 100644 --- a/extensions/renderer/module_system.cc +++ b/extensions/renderer/module_system.cc
@@ -6,6 +6,7 @@ #include "base/bind.h" #include "base/command_line.h" +#include "base/logging.h" #include "base/stl_util.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" @@ -151,12 +152,10 @@ } } -ModuleSystem::~ModuleSystem() { Invalidate(); } +ModuleSystem::~ModuleSystem() { +} void ModuleSystem::Invalidate() { - if (!is_valid()) - return; - // Clear the module system properties from the global context. It's polite, // and we use this as a signal in lazy handlers that we no longer exist. { @@ -168,12 +167,11 @@ v8::String::NewFromUtf8(GetIsolate(), kModuleSystem)); } - // Invalidate all of the successfully required handlers we own. - for (NativeHandlerMap::iterator it = native_handler_map_.begin(); - it != native_handler_map_.end(); - ++it) { - it->second->Invalidate(); - } + // Invalidate all active and clobbered NativeHandlers we own. + for (const auto& handler : native_handler_map_) + handler.second->Invalidate(); + for (const auto& clobbered_handler : clobbered_native_handlers_) + clobbered_handler->Invalidate(); ObjectBackedNativeHandler::Invalidate(); } @@ -301,11 +299,13 @@ void ModuleSystem::RegisterNativeHandler( const std::string& name, scoped_ptr<NativeHandler> native_handler) { + ClobberExistingNativeHandler(name); native_handler_map_[name] = linked_ptr<NativeHandler>(native_handler.release()); } void ModuleSystem::OverrideNativeHandlerForTest(const std::string& name) { + ClobberExistingNativeHandler(name); overridden_native_handlers_.insert(name); } @@ -685,4 +685,12 @@ resolver_local->Resolve(value); } +void ModuleSystem::ClobberExistingNativeHandler(const std::string& name) { + NativeHandlerMap::iterator existing_handler = native_handler_map_.find(name); + if (existing_handler != native_handler_map_.end()) { + clobbered_native_handlers_.push_back(existing_handler->second); + native_handler_map_.erase(existing_handler); + } +} + } // namespace extensions
diff --git a/extensions/renderer/module_system.h b/extensions/renderer/module_system.h index 8b4a35c..ad89524e 100644 --- a/extensions/renderer/module_system.h +++ b/extensions/renderer/module_system.h
@@ -142,6 +142,7 @@ } protected: + friend class ModuleSystemTestEnvironment; friend class ScriptContext; void Invalidate() override; @@ -205,6 +206,10 @@ const std::string& id, const std::vector<std::string>& dependencies) override; + // Marks any existing NativeHandler named |name| as clobbered. + // See |clobbered_native_handlers_|. + void ClobberExistingNativeHandler(const std::string& name); + ScriptContext* context_; // A map from module names to the JS source for that module. GetSource() @@ -222,8 +227,16 @@ // tests. scoped_ptr<ExceptionHandler> exception_handler_; + // A set of native handlers that should actually be require()d as non-native + // handlers. This is used for tests to mock out native handlers in JS. std::set<std::string> overridden_native_handlers_; + // A list of NativeHandlers that have been clobbered, either due to + // registering a NativeHandler when one was already registered with the same + // name, or due to OverrideNativeHandlerForTest. This is needed so that they + // can be later Invalidated. It should only happen in tests. + std::vector<linked_ptr<NativeHandler>> clobbered_native_handlers_; + base::WeakPtrFactory<ModuleSystem> weak_factory_; DISALLOW_COPY_AND_ASSIGN(ModuleSystem);
diff --git a/extensions/renderer/module_system_test.cc b/extensions/renderer/module_system_test.cc index b9d4a4d..cc4cbfba 100644 --- a/extensions/renderer/module_system_test.cc +++ b/extensions/renderer/module_system_test.cc
@@ -157,7 +157,7 @@ ModuleSystemTestEnvironment::~ModuleSystemTestEnvironment() { if (context_->is_valid()) - context_->v8_context()->Exit(); + ShutdownModuleSystem(); } void ModuleSystemTestEnvironment::RegisterModule(const std::string& name, @@ -196,6 +196,7 @@ } void ModuleSystemTestEnvironment::ShutdownModuleSystem() { + CHECK(context_->is_valid()); context_->v8_context()->Exit(); context_->Invalidate(); }
diff --git a/extensions/renderer/native_handler.cc b/extensions/renderer/native_handler.cc index 896ef56..a8b343a 100644 --- a/extensions/renderer/native_handler.cc +++ b/extensions/renderer/native_handler.cc
@@ -4,12 +4,19 @@ #include "extensions/renderer/native_handler.h" +#include "base/logging.h" + namespace extensions { NativeHandler::NativeHandler() : is_valid_(true) {} -NativeHandler::~NativeHandler() {} +NativeHandler::~NativeHandler() { + CHECK(!is_valid_) << "NativeHandlers must be invalidated before destruction"; +} -void NativeHandler::Invalidate() { is_valid_ = false; } +void NativeHandler::Invalidate() { + CHECK(is_valid_); + is_valid_ = false; +} } // namespace extensions
diff --git a/extensions/renderer/native_handler.h b/extensions/renderer/native_handler.h index c0660c8..1491feb8 100644 --- a/extensions/renderer/native_handler.h +++ b/extensions/renderer/native_handler.h
@@ -29,6 +29,9 @@ // // Subclasses should override to invalidate their own V8 state. If they do // they must call their superclass' Invalidate(). + // + // Invalidate() will be called on destruction, if it hasn't already been. + // Subclasses don't need to do it themselves. virtual void Invalidate(); protected:
diff --git a/extensions/renderer/object_backed_native_handler.cc b/extensions/renderer/object_backed_native_handler.cc index 10bedc1..075f1d6 100644 --- a/extensions/renderer/object_backed_native_handler.cc +++ b/extensions/renderer/object_backed_native_handler.cc
@@ -25,7 +25,8 @@ v8::ObjectTemplate::New(context->isolate())) { } -ObjectBackedNativeHandler::~ObjectBackedNativeHandler() { Invalidate(); } +ObjectBackedNativeHandler::~ObjectBackedNativeHandler() { +} v8::Handle<v8::Object> ObjectBackedNativeHandler::NewInstance() { return v8::Local<v8::ObjectTemplate>::New(GetIsolate(), object_template_) @@ -75,9 +76,7 @@ } void ObjectBackedNativeHandler::Invalidate() { - if (!is_valid()) - return; - v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::Isolate* isolate = GetIsolate(); v8::HandleScope handle_scope(isolate); v8::Context::Scope context_scope(context_->v8_context()); @@ -90,9 +89,10 @@ handler_function_value.As<v8::External>()->Value()); data->Delete(v8::String::NewFromUtf8(isolate, kHandlerFunction)); } + router_data_.Clear(); object_template_.Reset(); - context_ = NULL; + NativeHandler::Invalidate(); }
diff --git a/extensions/renderer/object_backed_native_handler.h b/extensions/renderer/object_backed_native_handler.h index 7fe4b1fe3..843e13b 100644 --- a/extensions/renderer/object_backed_native_handler.h +++ b/extensions/renderer/object_backed_native_handler.h
@@ -38,6 +38,10 @@ // Installs a new 'route' from |name| to |handler_function|. This means that // NewInstance()s of this ObjectBackedNativeHandler will have a property // |name| which will be handled by |handler_function|. + // + // Routed functions are destroyed along with the destruction of this class, + // and are never called back into, therefore it's safe for |handler_function| + // to bind to base::Unretained. void RouteFunction(const std::string& name, const HandlerFunction& handler_function);
diff --git a/extensions/renderer/resources/event.js b/extensions/renderer/resources/event.js index f62ab0f..bb71297 100644 --- a/extensions/renderer/resources/event.js +++ b/extensions/renderer/resources/event.js
@@ -9,7 +9,6 @@ var sendRequest = require('sendRequest').sendRequest; var utils = require('utils'); var validate = require('schemaUtils').validate; - var unloadEvent = require('unload_event'); // Schemas for the rule-style functions on the events API that // only need to be generated occasionally, so populate them lazily. @@ -38,9 +37,6 @@ // A map of event names to the event object that is registered to that name. var attachedNamedEvents = {}; - // An array of all attached event objects, used for detaching on unload. - var allAttachedEvents = []; - // A map of functions that massage event arguments before they are dispatched. // Key is event name, value is function. var eventArgumentMassagers = {}; @@ -283,7 +279,6 @@ this.attachmentStrategy.onAddedListener(listener); if (this.listeners.length == 0) { - allAttachedEvents[allAttachedEvents.length] = this; if (this.eventName) { if (attachedNamedEvents[this.eventName]) { throw new Error("Event '" + this.eventName + @@ -307,9 +302,6 @@ this.attachmentStrategy.onRemovedListener(removedListener); if (this.listeners.length == 0) { - var i = $Array.indexOf(allAttachedEvents, this); - if (i >= 0) - delete allAttachedEvents[i]; if (this.eventName) { if (!attachedNamedEvents[this.eventName]) { throw new Error( @@ -498,14 +490,6 @@ ruleFunctionSchemas.getRules.parameters); } - unloadEvent.addListener(function() { - for (var i = 0; i < allAttachedEvents.length; ++i) { - var event = allAttachedEvents[i]; - if (event) - event.detach_(); - } - }); - var Event = utils.expose('Event', EventImpl, { functions: [ 'addListener', 'removeListener',
diff --git a/extensions/renderer/script_context.cc b/extensions/renderer/script_context.cc index e5677aa..c3f04fa 100644 --- a/extensions/renderer/script_context.cc +++ b/extensions/renderer/script_context.cc
@@ -80,7 +80,8 @@ Feature::Context context_type, const Extension* effective_extension, Feature::Context effective_context_type) - : v8_context_(v8_context->GetIsolate(), v8_context), + : is_valid_(true), + v8_context_(v8_context->GetIsolate(), v8_context), web_frame_(web_frame), extension_(extension), context_type_(context_type), @@ -107,17 +108,34 @@ << " extension id: " << GetExtensionID() << "\n" << " effective extension id: " << (effective_extension_.get() ? effective_extension_->id() : ""); - Invalidate(); + CHECK(!is_valid_) << "ScriptContexts must be invalidated before destruction"; } void ScriptContext::Invalidate() { - if (!is_valid()) - return; + CHECK(is_valid_); + is_valid_ = false; + + // TODO(kalman): Make ModuleSystem use AddInvalidationObserver. + // Ownership graph is a bit weird here. if (module_system_) module_system_->Invalidate(); - web_frame_ = NULL; - v8_context_.Reset(); + + // Swap |invalidate_observers_| to a local variable to clear it, and to make + // sure it's not mutated as we iterate. + std::vector<base::Closure> observers; + observers.swap(invalidate_observers_); + for (const base::Closure& observer : observers) { + observer.Run(); + } + DCHECK(invalidate_observers_.empty()) + << "Invalidation observers cannot be added during invalidation"; + runner_.reset(); + v8_context_.Reset(); +} + +void ScriptContext::AddInvalidationObserver(const base::Closure& observer) { + invalidate_observers_.push_back(observer); } const std::string& ScriptContext::GetExtensionID() const { @@ -144,7 +162,7 @@ v8::Context::Scope scope(v8_context()); blink::WebScopedMicrotaskSuppression suppression; - if (!is_valid()) { + if (!is_valid_) { return handle_scope.Escape( v8::Local<v8::Primitive>(v8::Undefined(isolate()))); }
diff --git a/extensions/renderer/script_context.h b/extensions/renderer/script_context.h index b6c90f2..10901e3 100644 --- a/extensions/renderer/script_context.h +++ b/extensions/renderer/script_context.h
@@ -6,8 +6,10 @@ #define EXTENSIONS_RENDERER_SCRIPT_CONTEXT_H_ #include <string> +#include <vector> #include "base/basictypes.h" +#include "base/callback.h" #include "base/compiler_specific.h" #include "extensions/common/features/feature.h" #include "extensions/common/permissions/api_permission_set.h" @@ -45,9 +47,13 @@ // ModuleSystem. void Invalidate(); + // Registers |observer| to be run when this context is invalidated. Closures + // are run immediately when Invalidate() is called, not in a message loop. + void AddInvalidationObserver(const base::Closure& observer); + // Returns true if this context is still valid, false if it isn't. // A context becomes invalid via Invalidate(). - bool is_valid() const { return !v8_context_.IsEmpty(); } + bool is_valid() const { return is_valid_; } v8::Handle<v8::Context> v8_context() const { return v8::Local<v8::Context>::New(isolate_, v8_context_); @@ -150,13 +156,15 @@ // extension. bool HasAPIPermission(APIPermission::ID permission) const; - protected: - // The v8 context the bindings are accessible to. - v8::Global<v8::Context> v8_context_; - private: class Runner; + // Whether this context is valid. + bool is_valid_; + + // The v8 context the bindings are accessible to. + v8::Global<v8::Context> v8_context_; + // The WebFrame associated with this context. This can be NULL because this // object can outlive is destroyed asynchronously. blink::WebFrame* web_frame_; @@ -185,6 +193,10 @@ // The set of capabilities granted to this context by extensions. APIPermissionSet content_capabilities_; + // A list of base::Closure instances as an observer interface for + // invalidation. + std::vector<base::Closure> invalidate_observers_; + v8::Isolate* isolate_; GURL url_;
diff --git a/extensions/renderer/script_context_set_unittest.cc b/extensions/renderer/script_context_set_unittest.cc index bf7c38d..cbc0a76c 100644 --- a/extensions/renderer/script_context_set_unittest.cc +++ b/extensions/renderer/script_context_set_unittest.cc
@@ -53,7 +53,7 @@ EXPECT_EQ(1u, set_copy.size()); // After removal, the context should be marked for destruction. - EXPECT_FALSE(context->web_frame()); + EXPECT_FALSE(context->is_valid()); // Run loop to do the actual deletion. loop.RunUntilIdle();
diff --git a/extensions/renderer/v8_schema_registry.cc b/extensions/renderer/v8_schema_registry.cc index 841c8cf..c08ca47 100644 --- a/extensions/renderer/v8_schema_registry.cc +++ b/extensions/renderer/v8_schema_registry.cc
@@ -29,6 +29,8 @@ base::Unretained(this))); } + ~SchemaRegistryNativeHandler() override { context_->Invalidate(); } + private: void GetSchema(const v8::FunctionCallbackInfo<v8::Value>& args) { args.GetReturnValue().Set(
diff --git a/google_apis/drive/drive_api_url_generator.cc b/google_apis/drive/drive_api_url_generator.cc index 285e754..f2d36fa 100644 --- a/google_apis/drive/drive_api_url_generator.cc +++ b/google_apis/drive/drive_api_url_generator.cc
@@ -29,6 +29,7 @@ const char kDriveV2FileTrashUrlFormat[] = "drive/v2/files/%s/trash"; const char kDriveV2UploadNewFileUrl[] = "upload/drive/v2/files"; const char kDriveV2UploadExistingFileUrlPrefix[] = "upload/drive/v2/files/"; +const char kDriveV2BatchUploadUrl[] = "upload/drive"; const char kDriveV2PermissionsUrlFormat[] = "drive/v2/files/%s/permissions"; const char kDriveV2DownloadUrlFormat[] = "host/%s"; const char kDriveV2ThumbnailUrlFormat[] = "thumb/%s?width=%d&height=%d"; @@ -288,4 +289,8 @@ net::EscapePath(resource_id).c_str(), width, height)); } +GURL DriveApiUrlGenerator::GetBatchUploadUrl() const { + return base_url_.Resolve(kDriveV2BatchUploadUrl); +} + } // namespace google_apis
diff --git a/google_apis/drive/drive_api_url_generator.h b/google_apis/drive/drive_api_url_generator.h index ab623e30..dbdc6c7 100644 --- a/google_apis/drive/drive_api_url_generator.h +++ b/google_apis/drive/drive_api_url_generator.h
@@ -112,6 +112,9 @@ int width, int height) const; + // Generates a URL for batch upload. + GURL GetBatchUploadUrl() const; + private: const GURL base_url_; const GURL base_download_url_;
diff --git a/google_apis/drive/drive_api_url_generator_unittest.cc b/google_apis/drive/drive_api_url_generator_unittest.cc index 03e4c02d..92e128e 100644 --- a/google_apis/drive/drive_api_url_generator_unittest.cc +++ b/google_apis/drive/drive_api_url_generator_unittest.cc
@@ -363,4 +363,10 @@ url_generator_.GetThumbnailUrl("0ADK06pfg", 500, 500).spec()); } +TEST_F(DriveApiUrlGeneratorTest, BatchUploadUrl) { + EXPECT_EQ( + "https://www.example.com/upload/drive", + url_generator_.GetBatchUploadUrl().spec()); +} + } // namespace google_apis
diff --git a/google_apis/gcm/engine/connection_factory_impl.cc b/google_apis/gcm/engine/connection_factory_impl.cc index 5be2eb6..ec2fdea 100644 --- a/google_apis/gcm/engine/connection_factory_impl.cc +++ b/google_apis/gcm/engine/connection_factory_impl.cc
@@ -7,6 +7,7 @@ #include "base/message_loop/message_loop.h" #include "base/metrics/histogram.h" #include "base/metrics/sparse_histogram.h" +#include "base/profiler/scoped_tracker.h" #include "google_apis/gcm/engine/connection_handler_impl.h" #include "google_apis/gcm/monitoring/gcm_stats_recorder.h" #include "google_apis/gcm/protocol/mcs.pb.h" @@ -349,6 +350,10 @@ } void ConnectionFactoryImpl::OnConnectDone(int result) { + // TODO(pkasting): Remove ScopedTracker below once crbug.com/455884 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "455884 ConnectionFactoryImpl::OnConnectDone")); if (result != net::OK) { // If the connection fails, try another proxy. result = ReconsiderProxyAfterError(result);
diff --git a/gpu/DEPS b/gpu/DEPS index 6b8aacb..1b002bcc 100644 --- a/gpu/DEPS +++ b/gpu/DEPS
@@ -8,4 +8,5 @@ "+ui/gfx", "+ui/gl", "+ui/surface", + "+ui/ozone/public", ]
diff --git a/gpu/command_buffer/client/cmd_buffer_helper_test.cc b/gpu/command_buffer/client/cmd_buffer_helper_test.cc index ac83da5..6348abb 100644 --- a/gpu/command_buffer/client/cmd_buffer_helper_test.cc +++ b/gpu/command_buffer/client/cmd_buffer_helper_test.cc
@@ -9,7 +9,6 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/memory/linked_ptr.h" -#include "base/message_loop/message_loop.h" #include "gpu/command_buffer/client/cmd_buffer_helper.h" #include "gpu/command_buffer/service/command_buffer_service.h" #include "gpu/command_buffer/service/gpu_scheduler.h" @@ -17,10 +16,6 @@ #include "gpu/command_buffer/service/transfer_buffer_manager.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(OS_MACOSX) -#include "base/mac/scoped_nsautorelease_pool.h" -#endif - namespace gpu { using testing::Return; @@ -256,10 +251,6 @@ CommandBufferOffset get_helper_put() { return helper_->put_; } -#if defined(OS_MACOSX) - base::mac::ScopedNSAutoreleasePool autorelease_pool_; -#endif - base::MessageLoop message_loop_; scoped_ptr<AsyncAPIMock> api_mock_; scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_; scoped_ptr<CommandBufferServiceLocked> command_buffer_;
diff --git a/gpu/command_buffer/client/fenced_allocator_test.cc b/gpu/command_buffer/client/fenced_allocator_test.cc index 3af9367..6b9f00f4 100644 --- a/gpu/command_buffer/client/fenced_allocator_test.cc +++ b/gpu/command_buffer/client/fenced_allocator_test.cc
@@ -7,7 +7,6 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/memory/aligned_memory.h" -#include "base/message_loop/message_loop.h" #include "gpu/command_buffer/client/cmd_buffer_helper.h" #include "gpu/command_buffer/client/fenced_allocator.h" #include "gpu/command_buffer/service/cmd_buffer_engine.h" @@ -17,10 +16,6 @@ #include "gpu/command_buffer/service/transfer_buffer_manager.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(OS_MACOSX) -#include "base/mac/scoped_nsautorelease_pool.h" -#endif - namespace gpu { using testing::Return; @@ -74,10 +69,6 @@ return command_buffer_->GetLastState().token; } -#if defined(OS_MACOSX) - base::mac::ScopedNSAutoreleasePool autorelease_pool_; -#endif - base::MessageLoop message_loop_; scoped_ptr<AsyncAPIMock> api_mock_; scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_; scoped_ptr<CommandBufferService> command_buffer_;
diff --git a/gpu/command_buffer/client/mapped_memory_unittest.cc b/gpu/command_buffer/client/mapped_memory_unittest.cc index 9d5bada..6430b667 100644 --- a/gpu/command_buffer/client/mapped_memory_unittest.cc +++ b/gpu/command_buffer/client/mapped_memory_unittest.cc
@@ -15,10 +15,6 @@ #include "gpu/command_buffer/service/transfer_buffer_manager.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(OS_MACOSX) -#include "base/mac/scoped_nsautorelease_pool.h" -#endif - namespace gpu { using testing::Return; @@ -71,10 +67,6 @@ return command_buffer_->GetLastState().token; } -#if defined(OS_MACOSX) - base::mac::ScopedNSAutoreleasePool autorelease_pool_; -#endif - base::MessageLoop message_loop_; scoped_ptr<AsyncAPIMock> api_mock_; scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_; scoped_ptr<CommandBufferService> command_buffer_;
diff --git a/gpu/command_buffer/client/ring_buffer_test.cc b/gpu/command_buffer/client/ring_buffer_test.cc index c1aab88..ac5634a 100644 --- a/gpu/command_buffer/client/ring_buffer_test.cc +++ b/gpu/command_buffer/client/ring_buffer_test.cc
@@ -8,7 +8,6 @@ #include "base/bind.h" #include "base/bind_helpers.h" -#include "base/message_loop/message_loop.h" #include "gpu/command_buffer/client/cmd_buffer_helper.h" #include "gpu/command_buffer/service/cmd_buffer_engine.h" #include "gpu/command_buffer/service/command_buffer_service.h" @@ -17,10 +16,6 @@ #include "gpu/command_buffer/service/transfer_buffer_manager.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(OS_MACOSX) -#include "base/mac/scoped_nsautorelease_pool.h" -#endif - namespace gpu { using testing::Return; @@ -96,10 +91,6 @@ return command_buffer_->GetLastState().token; } -#if defined(OS_MACOSX) - base::mac::ScopedNSAutoreleasePool autorelease_pool_; -#endif - base::MessageLoop message_loop_; scoped_ptr<AsyncAPIMock> api_mock_; scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_; scoped_ptr<CommandBufferService> command_buffer_;
diff --git a/gpu/command_buffer/common/unittest_main.cc b/gpu/command_buffer/common/unittest_main.cc index 874bae7..17b6114 100644 --- a/gpu/command_buffer/common/unittest_main.cc +++ b/gpu/command_buffer/common/unittest_main.cc
@@ -5,11 +5,16 @@ #include "base/at_exit.h" #include "base/bind.h" #include "base/command_line.h" +#include "base/message_loop/message_loop.h" #include "base/test/launcher/unit_test_launcher.h" #include "base/test/test_suite.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#if defined(OS_MACOSX) +#include "base/mac/scoped_nsautorelease_pool.h" +#endif + namespace { class NoAtExitBaseTestSuite : public base::TestSuite { @@ -20,6 +25,7 @@ }; int RunTestSuite(int argc, char** argv) { + base::MessageLoop message_loop; return NoAtExitBaseTestSuite(argc, argv).Run(); } @@ -33,6 +39,9 @@ base::AtExitManager exit_manager; #endif base::CommandLine::Init(argc, argv); +#if defined(OS_MACOSX) + base::mac::ScopedNSAutoreleasePool autorelease_pool; +#endif testing::InitGoogleMock(&argc, argv); return base::LaunchUnitTests(argc, argv,
diff --git a/gpu/command_buffer/service/gpu_scheduler_unittest.cc b/gpu/command_buffer/service/gpu_scheduler_unittest.cc index c1c0d1c..c1c2ef7 100644 --- a/gpu/command_buffer/service/gpu_scheduler_unittest.cc +++ b/gpu/command_buffer/service/gpu_scheduler_unittest.cc
@@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/message_loop/message_loop.h" #include "gpu/command_buffer/common/command_buffer_mock.h" #include "gpu/command_buffer/service/gles2_cmd_decoder.h" #include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h" @@ -11,10 +10,6 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(OS_MACOSX) -#include "base/mac/scoped_nsautorelease_pool.h" -#endif - using testing::_; using testing::DoAll; using testing::Invoke; @@ -72,10 +67,6 @@ return command_buffer_->GetLastState().error; } -#if defined(OS_MACOSX) - base::mac::ScopedNSAutoreleasePool autorelease_pool_; -#endif - base::MessageLoop message_loop; scoped_ptr<MockCommandBuffer> command_buffer_; scoped_refptr<Buffer> shared_memory_buffer_; int32* buffer_;
diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc index e4ed83d5..0196e3b 100644 --- a/gpu/command_buffer/tests/gl_manager.cc +++ b/gpu/command_buffer/tests/gl_manager.cc
@@ -302,7 +302,7 @@ decoder_->set_engine(gpu_scheduler_.get()); - surface_ = gfx::GLSurface::CreateOffscreenGLSurface(options.size); + surface_ = gfx::GLSurface::CreateOffscreenGLSurface(gfx::Size()); ASSERT_TRUE(surface_.get() != NULL) << "could not create offscreen surface"; if (base_context_) {
diff --git a/gpu/command_buffer/tests/gl_tests_main.cc b/gpu/command_buffer/tests/gl_tests_main.cc index 7b7d8d86..6ac5719 100644 --- a/gpu/command_buffer/tests/gl_tests_main.cc +++ b/gpu/command_buffer/tests/gl_tests_main.cc
@@ -24,7 +24,14 @@ namespace { int RunHelper(base::TestSuite* testSuite) { +#if defined(USE_OZONE) + base::MessageLoopForUI main_loop; +#else base::MessageLoopForIO message_loop; +#endif + gfx::GLSurface::InitializeOneOff(); + ::gles2::Initialize(); + gpu::ApplyGpuDriverBugWorkarounds(base::CommandLine::ForCurrentProcess()); return testSuite->Run(); } @@ -39,9 +46,6 @@ #if defined(OS_MACOSX) base::mac::ScopedNSAutoreleasePool pool; #endif - gfx::GLSurface::InitializeOneOff(); - ::gles2::Initialize(); - gpu::ApplyGpuDriverBugWorkarounds(base::CommandLine::ForCurrentProcess()); testing::InitGoogleMock(&argc, argv); return base::LaunchUnitTestsSerially( argc,
diff --git a/gpu/config/software_rendering_list_json.cc b/gpu/config/software_rendering_list_json.cc index 7d3d890..0a9a8d8 100644 --- a/gpu/config/software_rendering_list_json.cc +++ b/gpu/config/software_rendering_list_json.cc
@@ -18,7 +18,7 @@ { "name": "software rendering list", // Please update the version number whenever you change this file. - "version": "10.3", + "version": "10.4", "entries": [ { "id": 1, @@ -331,6 +331,11 @@ }, "vendor_id": "0x10de", "gl_vendor": "(?i)nouveau.*", + "driver_vendor": "Mesa", + "driver_version": { + "op": "<", + "value": "10.1" + }, "features": [ "all" ] @@ -349,17 +354,6 @@ ] }, { - "id": 35, - "description": "Stage3D is not supported on Linux", - "cr_bugs": [129848], - "os": { - "type": "linux" - }, - "features": [ - "flash_stage3d" - ] - }, - { "id": 37, "description": "Older drivers are unreliable for Optimus on Linux", "cr_bugs": [131308, 363418],
diff --git a/ios/chrome/DEPS b/ios/chrome/DEPS index f23eea2a..6503a0e 100644 --- a/ios/chrome/DEPS +++ b/ios/chrome/DEPS
@@ -2,36 +2,4 @@ # The subdirectories in ios/chrome/ will manually allow their own include # directories in ios/chrome/ so we disallow all of them. "-ios/chrome", - "+ios/chrome/grit", - - "+components/autofill/core/browser", - "+components/autofill/ios/browser", - "+components/data_reduction_proxy/core/common", - "+components/dom_distiller/core", - "+components/dom_distiller/ios", - "+components/infobars/core", - "+components/keyed_service/core", - "+components/keyed_service/ios", - "+components/leveldb_proto", - "+components/suggestions", - "+components/translate/core", - "+components/translate/ios", - "+components/web_resource", - "+components/webp_transcode", - "+ios/net", - "+ios/public/provider/chrome", - "+ios/web/public", - "+net", - "+third_party/google_toolbox_for_mac", - "+ui", - - # For tests. - "+ios/public/test", - - # Only parts of skia are compiled on iOS, so we explicitly list the - # files that can be included to avoid bringing in more code. - "+skia/ext/skia_utils_ios.h", - - # Generated file for translated strings in components. - "+grit/components_strings.h", ]
diff --git a/ios/chrome/browser/DEPS b/ios/chrome/browser/DEPS new file mode 100644 index 0000000..f34a686 --- /dev/null +++ b/ios/chrome/browser/DEPS
@@ -0,0 +1,34 @@ +include_rules = [ + "+ios/chrome/grit", + + "+components/autofill/core/browser", + "+components/autofill/ios/browser", + "+components/data_reduction_proxy/core/common", + "+components/dom_distiller/core", + "+components/dom_distiller/ios", + "+components/infobars/core", + "+components/keyed_service/core", + "+components/keyed_service/ios", + "+components/leveldb_proto", + "+components/suggestions", + "+components/translate/core", + "+components/translate/ios", + "+components/web_resource", + "+components/webp_transcode", + "+ios/net", + "+ios/public/provider/chrome", + "+ios/web/public", + "+net", + "+third_party/google_toolbox_for_mac", + "+ui", + + # For tests. + "+ios/public/test", + + # Only parts of skia are compiled on iOS, so we explicitly list the + # files that can be included to avoid bringing in more code. + "+skia/ext/skia_utils_ios.h", + + # Generated file for translated strings in components. + "+grit/components_strings.h", +]
diff --git a/ios/chrome/common/README.txt b/ios/chrome/common/README.txt new file mode 100644 index 0000000..72023cf --- /dev/null +++ b/ios/chrome/common/README.txt
@@ -0,0 +1,2 @@ +This directory holds code shared by Chrome and Chrome iOS extensions. +
diff --git a/ios/chrome/common/string_util.h b/ios/chrome/common/string_util.h new file mode 100644 index 0000000..9176a3a8 --- /dev/null +++ b/ios/chrome/common/string_util.h
@@ -0,0 +1,44 @@ +// 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 IOS_CHROME_COMMON_STRING_UTIL_H_ +#define IOS_CHROME_COMMON_STRING_UTIL_H_ + +#import <CoreGraphics/CoreGraphics.h> +#import <Foundation/Foundation.h> +#include <string> + +// Parses a string with an embedded link inside, delineated by BEGIN_LINK and +// END_LINK. Returns the string without the link delimiters. If |out_link_range| +// is not null, then it is filled out with the range of the link in the returned +// string. +// If no link is found, then it returns |text| and sets |out_link_range| to +// {NSNotFound, 0}. +NSString* ParseStringWithLink(NSString* text, NSRange* out_link_range); + +// Utility method that returns an NSCharacterSet containing Unicode graphics +// and drawing characters (but not including the Braille Patterns characters). +NSCharacterSet* GraphicCharactersSet(); + +// Cleans an NSString by collapsing whitespace and (if |trim| is true) +// removing leading and trailing spaces. If |removeGraphicChars| is true, +// unicode graphic characters will also be removed from the string. +NSString* CleanNSStringForDisplay(NSString* dirty, + BOOL removeGraphicChars, + BOOL trim); + +// Cleans a std::string identically to CleanNSStringForDisplay() +std::string CleanStringForDisplay(std::string dirty, + BOOL removeGraphicChars, + BOOL trim); + +// Find the longest leading substring of |string| that, when rendered with +// |attributes|, will fit on a single line inside |targetWidth|. If |trailing| +// is YES, then find the trailing (instead of leading) substring. +NSString* SubstringOfWidth(NSString* string, + NSDictionary* attributes, + CGFloat targetWidth, + BOOL trailing); + +#endif // IOS_CHROME_COMMON_STRING_UTIL_H_
diff --git a/ios/chrome/common/string_util.mm b/ios/chrome/common/string_util.mm new file mode 100644 index 0000000..1d0510a --- /dev/null +++ b/ios/chrome/common/string_util.mm
@@ -0,0 +1,184 @@ +// 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 "ios/chrome/common/string_util.h" + +#import <UIKit/UIKit.h> + +#include "base/logging.h" +#include "base/mac/scoped_block.h" +#include "base/mac/scoped_nsobject.h" +#include "base/strings/stringprintf.h" +#include "base/strings/sys_string_conversions.h" + +namespace { +typedef BOOL (^ArrayFilterProcedure)(id object, NSUInteger index, BOOL* stop); +typedef NSString* (^SubstringExtractionProcedure)(NSUInteger); +} + +NSString* ParseStringWithLink(NSString* text, NSRange* out_link_range) { + // Find the range within |text| and create a substring without the link tags. + NSRange begin_range = [text rangeOfString:@"BEGIN_LINK[ \t]*" + options:NSRegularExpressionSearch]; + NSRange link_text_range = NSMakeRange(NSNotFound, 0); + if (begin_range.length == 0) { + if (out_link_range) + *out_link_range = link_text_range; + return text; + } + + NSUInteger after_begin_link = NSMaxRange(begin_range); + NSRange range_to_search_for_end_link = + NSMakeRange(after_begin_link, text.length - after_begin_link); + NSRange end_range = [text rangeOfString:@"[ \t]*END_LINK" + options:NSRegularExpressionSearch + range:range_to_search_for_end_link]; + if (end_range.length == 0) { + if (out_link_range) + *out_link_range = link_text_range; + return text; + } + + link_text_range.location = after_begin_link; + link_text_range.length = end_range.location - link_text_range.location; + base::scoped_nsobject<NSMutableString> out_text( + [[NSMutableString alloc] init]); + // First part - before the link. + if (begin_range.location > 0) + [out_text appendString:[text substringToIndex:begin_range.location]]; + + // Link part. + [out_text appendString:[text substringWithRange:link_text_range]]; + + // Last part - after the link. + NSUInteger after_end_link = NSMaxRange(end_range); + if (after_end_link < [text length]) { + [out_text appendString:[text substringFromIndex:after_end_link]]; + } + + link_text_range.location = begin_range.location; + if (out_link_range) + *out_link_range = link_text_range; + return [NSString stringWithString:out_text]; +} + +// Ranges of unicode codepage containing drawing characters. +// 2190—21FF Arrows +// 2200—22FF Mathematical Operators +// 2300—23FF Miscellaneous Technical +// 2400—243F Control Pictures +// 2440—245F Optical Character Recognition +// 2460—24FF Enclosed Alphanumerics +// 2500—257F Box Drawing +// 2580—259F Block Elements +// 25A0—25FF Geometric Shapes +// 2600—26FF Miscellaneous Symbols +// 2700—27BF Dingbats +// 27C0—27EF Miscellaneous Mathematical Symbols-A +// 27F0—27FF Supplemental Arrows-A +// 2900—297F Supplemental Arrows-B +// 2980—29FF Miscellaneous Mathematical Symbols-B +// 2A00—2AFF Supplemental Mathematical Operators +// 2B00—2BFF Miscellaneous Symbols and Arrows +// The section 2800—28FF Braille Patterns must be preserved. +// The list of characters that must be deleted from the selection. +NSCharacterSet* GraphicCharactersSet() { + static NSMutableCharacterSet* graphicalCharsSet; + static dispatch_once_t dispatch_once_token; + dispatch_once(&dispatch_once_token, ^{ + graphicalCharsSet = [[NSMutableCharacterSet alloc] init]; + NSRange graphicalCharsFirstRange = NSMakeRange(0x2190, 0x2800 - 0x2190); + NSRange graphicalCharsSecondRange = NSMakeRange(0x2900, 0x2c00 - 0x2900); + [graphicalCharsSet addCharactersInRange:graphicalCharsFirstRange]; + [graphicalCharsSet addCharactersInRange:graphicalCharsSecondRange]; + }); + return graphicalCharsSet; +} + +// TODO(marq): Add unit tests for this function. +NSString* CleanNSStringForDisplay(NSString* dirty, + BOOL removeGraphicChars, + BOOL trim) { + NSCharacterSet* wspace = [NSCharacterSet whitespaceAndNewlineCharacterSet]; + NSString* cleanString = dirty; + if (removeGraphicChars) { + cleanString = [[cleanString + componentsSeparatedByCharactersInSet:GraphicCharactersSet()] + componentsJoinedByString:@" "]; + } + base::scoped_nsobject<NSMutableArray> spaceSeparatedCompoments( + [[cleanString componentsSeparatedByCharactersInSet:wspace] mutableCopy]); + ArrayFilterProcedure filter = ^(id object, NSUInteger index, BOOL* stop) { + return [object isEqualToString:@""]; + }; + [spaceSeparatedCompoments + removeObjectsAtIndexes:[spaceSeparatedCompoments + indexesOfObjectsPassingTest:filter]]; + cleanString = [spaceSeparatedCompoments componentsJoinedByString:@" "]; + return trim ? [cleanString stringByTrimmingCharactersInSet:wspace] + : cleanString; +} + +std::string CleanStringForDisplay(std::string dirty, + BOOL removeGraphicChars, + BOOL trim) { + return base::SysNSStringToUTF8(CleanNSStringForDisplay( + base::SysUTF8ToNSString(dirty), removeGraphicChars, trim)); +} + +// TODO(marq): Add unit tests for this function. +NSString* SubstringOfWidth(NSString* string, + NSDictionary* attributes, + CGFloat targetWidth, + BOOL trailing) { + if (![string length]) + return nil; + + UIFont* font = [attributes objectForKey:NSFontAttributeName]; + DCHECK(font); + + // Function to get the correct substring while insulating against + // length overrun/underrun. + base::mac::ScopedBlock<SubstringExtractionProcedure> getSubstring; + if (trailing) { + getSubstring.reset([^NSString*(NSUInteger chars) { + NSUInteger length = [string length]; + return [string substringFromIndex:length - MIN(length, chars)]; + } copy]); + } else { + getSubstring.reset([^NSString*(NSUInteger chars) { + return [string substringToIndex:MIN(chars, [string length])]; + } copy]); + } + + // Guess at the number of characters that will fit, assuming + // the font's x-height is about 25% wider than an average character (25% + // value was determined experimentally). + NSUInteger characters = + MIN(targetWidth / (font.xHeight * 0.8), [string length]); + NSInteger increment = 1; + NSString* substring = getSubstring.get()(characters); + CGFloat prevWidth = [substring sizeWithAttributes:attributes].width; + do { + characters += increment; + substring = getSubstring.get()(characters); + CGFloat thisWidth = [substring sizeWithAttributes:attributes].width; + if (prevWidth > targetWidth) { + if (thisWidth < targetWidth) + break; // Shrinking the string, found the right size. + else + increment = -1; // Shrink the string + } else if (prevWidth < targetWidth) { + if (thisWidth < targetWidth) + increment = 1; // Grow the string + else { + substring = getSubstring.get()(characters - increment); + break; // Growing the string, found the right size. + } + } + prevWidth = thisWidth; + } while (characters > 0 && characters < [string length]); + + return substring; +}
diff --git a/ios/chrome/common/string_util_unittest.mm b/ios/chrome/common/string_util_unittest.mm new file mode 100644 index 0000000..fb70bec --- /dev/null +++ b/ios/chrome/common/string_util_unittest.mm
@@ -0,0 +1,58 @@ +// 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 "ios/chrome/common/string_util.h" + +#include "base/mac/scoped_nsobject.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/gtest_mac.h" +#include "testing/platform_test.h" + +namespace { + +TEST(StringUtilTest, ParseStringWithLink) { + NSArray* const all_test_data = @[ + @{ + @"input" : @"Text without link.", + @"expected" : @"Text without link.", + @"link range" : [NSValue valueWithRange:NSMakeRange(NSNotFound, 0)] + }, + @{ + @"input" : @"Text with empty link BEGIN_LINK END_LINK.", + @"expected" : @"Text with empty link .", + @"link range" : [NSValue valueWithRange:NSMakeRange(21, 0)] + }, + @{ + @"input" : @"Text with BEGIN_LINK and no end link.", + @"expected" : @"Text with BEGIN_LINK and no end link.", + @"link range" : [NSValue valueWithRange:NSMakeRange(NSNotFound, 0)] + }, + @{ + @"input" : @"Text with valid BEGIN_LINK link END_LINK and spaces.", + @"expected" : @"Text with valid link and spaces.", + @"link range" : [NSValue valueWithRange:NSMakeRange(16, 4)] + }, + @{ + @"input" : @"Text with valid BEGIN_LINKlinkEND_LINK and no spaces.", + @"expected" : @"Text with valid link and no spaces.", + @"link range" : [NSValue valueWithRange:NSMakeRange(16, 4)] + } + ]; + for (NSDictionary* test_data : all_test_data) { + NSString* input_text = test_data[@"input"]; + NSString* expected_text = test_data[@"expected"]; + NSRange expected_range = [test_data[@"link range"] rangeValue]; + + EXPECT_NSEQ(expected_text, ParseStringWithLink(input_text, nullptr)); + + // Initialize |range| with some values that are not equal to the expected + // ones. + NSRange range = NSMakeRange(1000, 2000); + EXPECT_NSEQ(expected_text, ParseStringWithLink(input_text, &range)); + EXPECT_EQ(expected_range.location, range.location); + EXPECT_EQ(expected_range.length, range.length); + } +} + +} // namespace
diff --git a/ios/chrome/ios_chrome.gyp b/ios/chrome/ios_chrome.gyp index b2029dc..3b0d9992 100644 --- a/ios/chrome/ios_chrome.gyp +++ b/ios/chrome/ios_chrome.gyp
@@ -39,6 +39,7 @@ '../provider/ios_provider_chrome.gyp:ios_provider_chrome_browser', '../web/ios_web.gyp:ios_web', 'injected_js', + 'ios_chrome_common', 'ios_chrome_resources.gyp:ios_theme_resources_gen', ], 'link_settings': { @@ -199,6 +200,26 @@ ], }, { + 'target_name': 'ios_chrome_common', + 'type': 'static_library', + 'include_dirs': [ + '../..', + ], + 'dependencies': [ + '../../base/base.gyp:base', + ], + 'link_settings': { + 'libraries': [ + '$(SDKROOT)/System/Library/Frameworks/CoreGraphics.framework', + '$(SDKROOT)/System/Library/Frameworks/Foundation.framework', + ], + }, + 'sources': [ + 'common/string_util.h', + 'common/string_util.mm', + ] + }, + { 'target_name': 'injected_js', 'type': 'none', 'sources': [
diff --git a/ios/chrome/ios_chrome_tests.gyp b/ios/chrome/ios_chrome_tests.gyp index 7cea1a3..3af8d8f 100644 --- a/ios/chrome/ios_chrome_tests.gyp +++ b/ios/chrome/ios_chrome_tests.gyp
@@ -20,6 +20,7 @@ '../web/ios_web.gyp:ios_web', '../web/ios_web.gyp:test_support_ios_web', 'ios_chrome.gyp:ios_chrome_browser', + 'ios_chrome.gyp:ios_chrome_common', 'ios_chrome_test_support', ], 'sources': [ @@ -32,6 +33,7 @@ 'browser/ui/commands/set_up_for_testing_command_unittest.mm', 'browser/ui/ui_util_unittest.mm', 'browser/ui/uikit_ui_util_unittest.mm', + 'common/string_util_unittest.mm', ], }, {
diff --git a/ios/chrome/test/DEPS b/ios/chrome/test/DEPS index 9074a78..0614aac1 100644 --- a/ios/chrome/test/DEPS +++ b/ios/chrome/test/DEPS
@@ -1,3 +1,7 @@ include_rules = [ "+ios/chrome/browser", + "+ios/public/provider/chrome", + "+ios/public/test", + "+ios/web/public", + "+ui", ]
diff --git a/jingle/glue/proxy_resolving_client_socket.cc b/jingle/glue/proxy_resolving_client_socket.cc index 5a6e068..456e100 100644 --- a/jingle/glue/proxy_resolving_client_socket.cc +++ b/jingle/glue/proxy_resolving_client_socket.cc
@@ -9,6 +9,7 @@ #include "base/bind_helpers.h" #include "base/compiler_specific.h" #include "base/logging.h" +#include "base/profiler/scoped_tracker.h" #include "net/base/io_buffer.h" #include "net/base/load_flags.h" #include "net/base/net_errors.h" @@ -212,6 +213,10 @@ } void ProxyResolvingClientSocket::ProcessConnectDone(int status) { + // TODO(pkasting): Remove ScopedTracker below once crbug.com/455884 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "455884 ProxyResolvingClientSocket::OnConnectDone")); if (status != net::OK) { // If the connection fails, try another proxy. status = ReconsiderProxyAfterError(status);
diff --git a/media/base/cdm_factory.h b/media/base/cdm_factory.h index 2a9b42d..f9c5541b 100644 --- a/media/base/cdm_factory.h +++ b/media/base/cdm_factory.h
@@ -17,10 +17,14 @@ class MEDIA_EXPORT CdmFactory { public: + using CdmCreatedCB = base::Callback<void(scoped_ptr<MediaKeys>)>; + CdmFactory(); virtual ~CdmFactory(); - virtual scoped_ptr<MediaKeys> Create( + // Creates a CDM for |key_system| and returns it through |cdm_created_cb| + // asynchronously. + virtual void Create( const std::string& key_system, bool allow_distinctive_identifier, bool allow_persistent_state, @@ -29,7 +33,8 @@ const SessionClosedCB& session_closed_cb, const LegacySessionErrorCB& legacy_session_error_cb, const SessionKeysChangeCB& session_keys_change_cb, - const SessionExpirationUpdateCB& session_expiration_update_cb) = 0; + const SessionExpirationUpdateCB& session_expiration_update_cb, + const CdmCreatedCB& cdm_created_cb) = 0; private: DISALLOW_COPY_AND_ASSIGN(CdmFactory);
diff --git a/media/blink/cdm_session_adapter.cc b/media/blink/cdm_session_adapter.cc index 79f5054..8e62bcee 100644 --- a/media/blink/cdm_session_adapter.cc +++ b/media/blink/cdm_session_adapter.cc
@@ -13,6 +13,7 @@ #include "media/base/cdm_promise.h" #include "media/base/key_systems.h" #include "media/base/media_keys.h" +#include "media/blink/webcontentdecryptionmodule_impl.h" #include "media/blink/webcontentdecryptionmodulesession_impl.h" #include "url/gurl.h" @@ -26,33 +27,34 @@ CdmSessionAdapter::~CdmSessionAdapter() {} -bool CdmSessionAdapter::Initialize(CdmFactory* cdm_factory, - const std::string& key_system, - bool allow_distinctive_identifier, - bool allow_persistent_state, - const GURL& security_origin) { - key_system_ = key_system; - key_system_uma_prefix_ = - kMediaEME + GetKeySystemNameForUMA(key_system) + kDot; - +void CdmSessionAdapter::CreateCdm( + CdmFactory* cdm_factory, + const std::string& key_system, + bool allow_distinctive_identifier, + bool allow_persistent_state, + const GURL& security_origin, + blink::WebContentDecryptionModuleResult result) { + // Note: WebContentDecryptionModuleImpl::Create() calls this method without + // holding a reference to the CdmSessionAdapter. Bind OnCdmCreated() with + // |this| instead of |weak_this| to prevent |this| from being desctructed. base::WeakPtr<CdmSessionAdapter> weak_this = weak_ptr_factory_.GetWeakPtr(); - media_keys_ = cdm_factory->Create( + cdm_factory->Create( key_system, allow_distinctive_identifier, allow_persistent_state, security_origin, base::Bind(&CdmSessionAdapter::OnSessionMessage, weak_this), base::Bind(&CdmSessionAdapter::OnSessionClosed, weak_this), base::Bind(&CdmSessionAdapter::OnLegacySessionError, weak_this), base::Bind(&CdmSessionAdapter::OnSessionKeysChange, weak_this), - base::Bind(&CdmSessionAdapter::OnSessionExpirationUpdate, weak_this)); - return media_keys_.get() != nullptr; + base::Bind(&CdmSessionAdapter::OnSessionExpirationUpdate, weak_this), + base::Bind(&CdmSessionAdapter::OnCdmCreated, this, key_system, result)); } void CdmSessionAdapter::SetServerCertificate( const uint8* server_certificate, int server_certificate_length, scoped_ptr<SimpleCdmPromise> promise) { - media_keys_->SetServerCertificate( - server_certificate, server_certificate_length, promise.Pass()); + cdm_->SetServerCertificate(server_certificate, server_certificate_length, + promise.Pass()); } WebContentDecryptionModuleSessionImpl* CdmSessionAdapter::CreateSession() { @@ -81,37 +83,35 @@ int init_data_length, MediaKeys::SessionType session_type, scoped_ptr<NewSessionCdmPromise> promise) { - media_keys_->CreateSessionAndGenerateRequest(session_type, init_data_type, - init_data, init_data_length, - promise.Pass()); + cdm_->CreateSessionAndGenerateRequest(session_type, init_data_type, init_data, + init_data_length, promise.Pass()); } void CdmSessionAdapter::LoadSession(MediaKeys::SessionType session_type, const std::string& session_id, scoped_ptr<NewSessionCdmPromise> promise) { - media_keys_->LoadSession(session_type, session_id, promise.Pass()); + cdm_->LoadSession(session_type, session_id, promise.Pass()); } void CdmSessionAdapter::UpdateSession(const std::string& session_id, const uint8* response, int response_length, scoped_ptr<SimpleCdmPromise> promise) { - media_keys_->UpdateSession(session_id, response, response_length, - promise.Pass()); + cdm_->UpdateSession(session_id, response, response_length, promise.Pass()); } void CdmSessionAdapter::CloseSession(const std::string& session_id, scoped_ptr<SimpleCdmPromise> promise) { - media_keys_->CloseSession(session_id, promise.Pass()); + cdm_->CloseSession(session_id, promise.Pass()); } void CdmSessionAdapter::RemoveSession(const std::string& session_id, scoped_ptr<SimpleCdmPromise> promise) { - media_keys_->RemoveSession(session_id, promise.Pass()); + cdm_->RemoveSession(session_id, promise.Pass()); } CdmContext* CdmSessionAdapter::GetCdmContext() { - return media_keys_->GetCdmContext(); + return cdm_->GetCdmContext(); } const std::string& CdmSessionAdapter::GetKeySystem() const { @@ -122,6 +122,27 @@ return key_system_uma_prefix_; } +void CdmSessionAdapter::OnCdmCreated( + const std::string& key_system, + blink::WebContentDecryptionModuleResult result, + scoped_ptr<MediaKeys> cdm) { + DVLOG(2) << __FUNCTION__; + if (!cdm) { + result.completeWithError( + blink::WebContentDecryptionModuleExceptionNotSupportedError, 0, + "Failed to create the CDM instance."); + return; + } + + key_system_ = key_system; + key_system_uma_prefix_ = + kMediaEME + GetKeySystemNameForUMA(key_system) + kDot; + cdm_ = cdm.Pass(); + + result.completeWithContentDecryptionModule( + new WebContentDecryptionModuleImpl(this)); +} + void CdmSessionAdapter::OnSessionMessage( const std::string& session_id, MediaKeys::MessageType message_type,
diff --git a/media/blink/cdm_session_adapter.h b/media/blink/cdm_session_adapter.h index e35c4cb..5ed7550e 100644 --- a/media/blink/cdm_session_adapter.h +++ b/media/blink/cdm_session_adapter.h
@@ -13,6 +13,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "media/base/media_keys.h" +#include "third_party/WebKit/public/platform/WebContentDecryptionModuleResult.h" #include "third_party/WebKit/public/platform/WebContentDecryptionModuleSession.h" class GURL; @@ -30,12 +31,14 @@ public: CdmSessionAdapter(); - // Returns true on success. - bool Initialize(CdmFactory* cdm_factory, - const std::string& key_system, - bool allow_distinctive_identifier, - bool allow_persistent_state, - const GURL& security_origin); + // Creates the CDM for |key_system| using |cdm_factory| and returns the result + // via |result|. + void CreateCdm(CdmFactory* cdm_factory, + const std::string& key_system, + bool allow_distinctive_identifier, + bool allow_persistent_state, + const GURL& security_origin, + blink::WebContentDecryptionModuleResult result); // Provides a server certificate to be used to encrypt messages to the // license server. @@ -99,12 +102,19 @@ private: friend class base::RefCounted<CdmSessionAdapter>; + + // Session ID to WebContentDecryptionModuleSessionImpl mapping. typedef base::hash_map<std::string, base::WeakPtr<WebContentDecryptionModuleSessionImpl> > SessionMap; ~CdmSessionAdapter(); + // Callback for CreateCdm(). + void OnCdmCreated(const std::string& key_system, + blink::WebContentDecryptionModuleResult result, + scoped_ptr<MediaKeys> cdm); + // Callbacks for firing session events. void OnSessionMessage(const std::string& session_id, MediaKeys::MessageType message_type, @@ -125,7 +135,7 @@ WebContentDecryptionModuleSessionImpl* GetSession( const std::string& session_id); - scoped_ptr<MediaKeys> media_keys_; + scoped_ptr<MediaKeys> cdm_; SessionMap sessions_;
diff --git a/media/blink/encrypted_media_player_support.cc b/media/blink/encrypted_media_player_support.cc index a84e24c..cc11a2e 100644 --- a/media/blink/encrypted_media_player_support.cc +++ b/media/blink/encrypted_media_player_support.cc
@@ -116,12 +116,12 @@ CdmFactory* cdm_factory, blink::WebMediaPlayerClient* client, MediaPermission* media_permission, - const SetCdmContextCB& set_cdm_context_cb) + const CdmContextReadyCB& cdm_context_ready_cb) : cdm_factory_(cdm_factory), client_(client), media_permission_(media_permission), init_data_type_(EmeInitDataType::UNKNOWN), - set_cdm_context_cb_(set_cdm_context_cb) { + cdm_context_ready_cb_(cdm_context_ready_cb) { } EncryptedMediaPlayerSupport::~EncryptedMediaPlayerSupport() { @@ -155,43 +155,32 @@ if (!PrefixedIsSupportedConcreteKeySystem(key_system)) return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported; - // We do not support run-time switching between key systems for now. - if (current_key_system_.empty()) { - if (!proxy_decryptor_) { - proxy_decryptor_.reset(new ProxyDecryptor( - media_permission_, - BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupport::OnKeyAdded), - BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupport::OnKeyError), - BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupport::OnKeyMessage))); - } + if (!proxy_decryptor_) { + DCHECK(current_key_system_.empty()); + DCHECK(!cdm_context_ready_cb_.is_null()); + proxy_decryptor_.reset(new ProxyDecryptor( + media_permission_, + BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupport::OnKeyAdded), + BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupport::OnKeyError), + BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupport::OnKeyMessage))); GURL security_origin(frame->document().securityOrigin().toString()); - - if (!proxy_decryptor_->InitializeCDM(cdm_factory_, key_system, - security_origin)) { - return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported; - } - - if (proxy_decryptor_ && !set_cdm_context_cb_.is_null()) { - base::ResetAndReturn(&set_cdm_context_cb_) - .Run(proxy_decryptor_->GetCdmContext(), - base::Bind(&IgnoreCdmAttached)); - } - + proxy_decryptor_->CreateCdm(cdm_factory_, key_system, security_origin, + cdm_context_ready_cb_); current_key_system_ = key_system; - } else if (key_system != current_key_system_) { - return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState; } + // We do not support run-time switching between key systems for now. + DCHECK(!current_key_system_.empty()); + if (key_system != current_key_system_) + return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState; + EmeInitDataType init_data_type = init_data_type_; if (init_data_type == EmeInitDataType::UNKNOWN) init_data_type = GuessInitDataType(init_data, init_data_length); - if (!proxy_decryptor_->GenerateKeyRequest(init_data_type, init_data, - init_data_length)) { - current_key_system_.clear(); - return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported; - } + proxy_decryptor_->GenerateKeyRequest(init_data_type, init_data, + init_data_length); return WebMediaPlayer::MediaKeyExceptionNoError; }
diff --git a/media/blink/encrypted_media_player_support.h b/media/blink/encrypted_media_player_support.h index 30d87086..d3fd454b 100644 --- a/media/blink/encrypted_media_player_support.h +++ b/media/blink/encrypted_media_player_support.h
@@ -37,13 +37,13 @@ class EncryptedMediaPlayerSupport : public base::SupportsWeakPtr<EncryptedMediaPlayerSupport> { public: - typedef base::Callback<void(CdmContext*, const CdmAttachedCB&)> - SetCdmContextCB; + using CdmContextReadyCB = ProxyDecryptor::CdmContextReadyCB; + // |cdm_context_ready_cb| is called when the CDM instance creation completes. EncryptedMediaPlayerSupport(CdmFactory* cdm_factory, blink::WebMediaPlayerClient* client, MediaPermission* media_permission, - const SetCdmContextCB& set_cdm_context_cb); + const CdmContextReadyCB& cdm_context_ready_cb); ~EncryptedMediaPlayerSupport(); blink::WebMediaPlayer::MediaKeyException GenerateKeyRequest( @@ -109,7 +109,7 @@ // init data type. EmeInitDataType init_data_type_; - SetCdmContextCB set_cdm_context_cb_; + CdmContextReadyCB cdm_context_ready_cb_; // Manages decryption keys and decrypts encrypted frames. scoped_ptr<ProxyDecryptor> proxy_decryptor_;
diff --git a/media/blink/webcontentdecryptionmodule_impl.cc b/media/blink/webcontentdecryptionmodule_impl.cc index 9d60220..7bdd9c9e 100644 --- a/media/blink/webcontentdecryptionmodule_impl.cc +++ b/media/blink/webcontentdecryptionmodule_impl.cc
@@ -62,21 +62,15 @@ } GURL security_origin_as_gurl(security_origin.toString()); + + // CdmSessionAdapter::CreateCdm() will keep a reference to |adapter|. Then + // if WebContentDecryptionModuleImpl is successfully created (returned in + // |result|), it will keep a reference to |adapter|. Otherwise, |adapter| will + // be destructed. scoped_refptr<CdmSessionAdapter> adapter(new CdmSessionAdapter()); - - // TODO(jrummell): Pass WebContentDecryptionModuleResult (or similar) to - // Initialize() so that more specific errors can be reported. - if (!adapter->Initialize(cdm_factory, key_system_ascii, - allow_distinctive_identifier, - allow_persistent_state, security_origin_as_gurl)) { - result.completeWithError( - blink::WebContentDecryptionModuleExceptionNotSupportedError, 0, - "Failed to initialize CDM."); - return; - } - - result.completeWithContentDecryptionModule( - new WebContentDecryptionModuleImpl(adapter)); + adapter->CreateCdm(cdm_factory, key_system_ascii, + allow_distinctive_identifier, allow_persistent_state, + security_origin_as_gurl, result); } WebContentDecryptionModuleImpl::WebContentDecryptionModuleImpl(
diff --git a/media/blink/webcontentdecryptionmodule_impl.h b/media/blink/webcontentdecryptionmodule_impl.h index 8b38cc6b..aa7fa16 100644 --- a/media/blink/webcontentdecryptionmodule_impl.h +++ b/media/blink/webcontentdecryptionmodule_impl.h
@@ -52,6 +52,8 @@ CdmContext* GetCdmContext(); private: + friend CdmSessionAdapter; + // Takes reference to |adapter|. WebContentDecryptionModuleImpl(scoped_refptr<CdmSessionAdapter> adapter);
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc index fe30c5ef..ab62772 100644 --- a/media/blink/webmediaplayer_impl.cc +++ b/media/blink/webmediaplayer_impl.cc
@@ -137,11 +137,12 @@ compositor_(new VideoFrameCompositor( BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnNaturalSizeChanged), BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnOpacityChanged))), - encrypted_media_support_( - cdm_factory, - client, - params.media_permission(), - base::Bind(&WebMediaPlayerImpl::SetCdm, AsWeakPtr())), + encrypted_media_support_(cdm_factory, + client, + params.media_permission(), + base::Bind(&WebMediaPlayerImpl::SetCdm, + AsWeakPtr(), + base::Bind(&IgnoreCdmAttached))), renderer_factory_(renderer_factory.Pass()) { // Threaded compositing isn't enabled universally yet. if (!compositor_task_runner_.get()) @@ -151,9 +152,9 @@ media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_CREATED)); if (params.initial_cdm()) { - SetCdm( - ToWebContentDecryptionModuleImpl(params.initial_cdm())->GetCdmContext(), - base::Bind(&IgnoreCdmAttached)); + SetCdm(base::Bind(&IgnoreCdmAttached), + ToWebContentDecryptionModuleImpl(params.initial_cdm()) + ->GetCdmContext()); } // TODO(xhwang): When we use an external Renderer, many methods won't work, @@ -660,8 +661,8 @@ return; } - SetCdm(ToWebContentDecryptionModuleImpl(cdm)->GetCdmContext(), - BIND_TO_RENDER_LOOP1(&WebMediaPlayerImpl::OnCdmAttached, result)); + SetCdm(BIND_TO_RENDER_LOOP1(&WebMediaPlayerImpl::OnCdmAttached, result), + ToWebContentDecryptionModuleImpl(cdm)->GetCdmContext()); } void WebMediaPlayerImpl::OnEncryptedMediaInitData( @@ -695,8 +696,8 @@ client_->didResumePlaybackBlockedForKey(); } -void WebMediaPlayerImpl::SetCdm(CdmContext* cdm_context, - const CdmAttachedCB& cdm_attached_cb) { +void WebMediaPlayerImpl::SetCdm(const CdmAttachedCB& cdm_attached_cb, + CdmContext* cdm_context) { pipeline_.SetCdm(cdm_context, cdm_attached_cb); }
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h index 80bea8f3c..427357b1 100644 --- a/media/blink/webmediaplayer_impl.h +++ b/media/blink/webmediaplayer_impl.h
@@ -224,7 +224,9 @@ // is not available. void OnWaitingForDecryptionKey(); - void SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb); + // Sets |cdm_context| on the pipeline and fires |cdm_attached_cb| when done. + // Parameter order is reversed for easy binding. + void SetCdm(const CdmAttachedCB& cdm_attached_cb, CdmContext* cdm_context); // Called when a CDM has been attached to the |pipeline_|. void OnCdmAttached(blink::WebContentDecryptionModuleResult result,
diff --git a/media/cdm/default_cdm_factory.cc b/media/cdm/default_cdm_factory.cc index a87760c12..202f3cdc 100644 --- a/media/cdm/default_cdm_factory.cc +++ b/media/cdm/default_cdm_factory.cc
@@ -4,6 +4,10 @@ #include "media/cdm/default_cdm_factory.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/location.h" +#include "base/message_loop/message_loop_proxy.h" #include "media/base/key_systems.h" #include "media/cdm/aes_decryptor.h" #include "url/gurl.h" @@ -16,7 +20,7 @@ DefaultCdmFactory::~DefaultCdmFactory() { } -scoped_ptr<MediaKeys> DefaultCdmFactory::Create( +void DefaultCdmFactory::Create( const std::string& key_system, bool allow_distinctive_identifier, bool allow_persistent_state, @@ -25,17 +29,19 @@ const SessionClosedCB& session_closed_cb, const LegacySessionErrorCB& legacy_session_error_cb, const SessionKeysChangeCB& session_keys_change_cb, - const SessionExpirationUpdateCB& session_expiration_update_cb) { - if (!security_origin.is_valid()) - return nullptr; - - if (CanUseAesDecryptor(key_system)) { - return make_scoped_ptr(new AesDecryptor(security_origin, session_message_cb, - session_closed_cb, - session_keys_change_cb)); + const SessionExpirationUpdateCB& session_expiration_update_cb, + const CdmCreatedCB& cdm_created_cb) { + if (!security_origin.is_valid() || !CanUseAesDecryptor(key_system)) { + base::MessageLoopProxy::current()->PostTask( + FROM_HERE, base::Bind(cdm_created_cb, nullptr)); + return; } - return nullptr; + scoped_ptr<MediaKeys> cdm( + new AesDecryptor(security_origin, session_message_cb, session_closed_cb, + session_keys_change_cb)); + base::MessageLoopProxy::current()->PostTask( + FROM_HERE, base::Bind(cdm_created_cb, base::Passed(&cdm))); } } // namespace media
diff --git a/media/cdm/default_cdm_factory.h b/media/cdm/default_cdm_factory.h index 72e0e8d..7060c7c4 100644 --- a/media/cdm/default_cdm_factory.h +++ b/media/cdm/default_cdm_factory.h
@@ -16,16 +16,16 @@ ~DefaultCdmFactory() final; // CdmFactory implementation. - scoped_ptr<MediaKeys> Create( - const std::string& key_system, - bool allow_distinctive_identifier, - bool allow_persistent_state, - const GURL& security_origin, - const SessionMessageCB& session_message_cb, - const SessionClosedCB& session_closed_cb, - const LegacySessionErrorCB& legacy_session_error_cb, - const SessionKeysChangeCB& session_keys_change_cb, - const SessionExpirationUpdateCB& session_expiration_update_cb) final; + void Create(const std::string& key_system, + bool allow_distinctive_identifier, + bool allow_persistent_state, + const GURL& security_origin, + const SessionMessageCB& session_message_cb, + const SessionClosedCB& session_closed_cb, + const LegacySessionErrorCB& legacy_session_error_cb, + const SessionKeysChangeCB& session_keys_change_cb, + const SessionExpirationUpdateCB& session_expiration_update_cb, + const CdmCreatedCB& cdm_created_cb) final; private: DISALLOW_COPY_AND_ASSIGN(DefaultCdmFactory);
diff --git a/media/cdm/json_web_key.cc b/media/cdm/json_web_key.cc index 21df8377..43533f0 100644 --- a/media/cdm/json_web_key.cc +++ b/media/cdm/json_web_key.cc
@@ -19,8 +19,6 @@ const char kKeysTag[] = "keys"; const char kKeyTypeTag[] = "kty"; const char kKeyTypeOct[] = "oct"; // Octet sequence. -const char kAlgTag[] = "alg"; -const char kAlgA128KW[] = "A128KW"; // AES key wrap using a 128-bit key. const char kKeyTag[] = "k"; const char kKeyIdTag[] = "kid"; const char kKeyIdsTag[] = "kids"; @@ -113,7 +111,6 @@ // Create the JWK, and wrap it into a JWK Set. scoped_ptr<base::DictionaryValue> jwk(new base::DictionaryValue()); jwk->SetString(kKeyTypeTag, kKeyTypeOct); - jwk->SetString(kAlgTag, kAlgA128KW); jwk->SetString(kKeyTag, key_base64); jwk->SetString(kKeyIdTag, key_id_base64); scoped_ptr<base::ListValue> list(new base::ListValue()); @@ -138,12 +135,6 @@ return false; } - std::string alg; - if (!jwk.GetString(kAlgTag, &alg) || alg != kAlgA128KW) { - DVLOG(1) << "Missing or invalid '" << kAlgTag << "': " << alg; - return false; - } - // Get the key id and actual key parameters. std::string encoded_key_id; std::string encoded_key;
diff --git a/media/cdm/json_web_key_unittest.cc b/media/cdm/json_web_key_unittest.cc index 0cb251c..ecd9d2a 100644 --- a/media/cdm/json_web_key_unittest.cc +++ b/media/cdm/json_web_key_unittest.cc
@@ -79,24 +79,17 @@ const uint8 data3[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 }; + EXPECT_EQ("{\"keys\":[{\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}]}", + GenerateJWKSet(data1, arraysize(data1), data1, arraysize(data1))); EXPECT_EQ( - "{\"keys\":[{\"alg\":\"A128KW\",\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":" - "\"oct\"}]}", - GenerateJWKSet(data1, arraysize(data1), data1, arraysize(data1))); - EXPECT_EQ( - "{\"keys\":[{\"alg\":\"A128KW\",\"k\":\"AQIDBA\",\"kid\":\"AQIDBA\"," - "\"kty\":\"oct\"}]}", + "{\"keys\":[{\"k\":\"AQIDBA\",\"kid\":\"AQIDBA\",\"kty\":\"oct\"}]}", GenerateJWKSet(data2, arraysize(data2), data2, arraysize(data2))); + EXPECT_EQ("{\"keys\":[{\"k\":\"AQI\",\"kid\":\"AQIDBA\",\"kty\":\"oct\"}]}", + GenerateJWKSet(data1, arraysize(data1), data2, arraysize(data2))); + EXPECT_EQ("{\"keys\":[{\"k\":\"AQIDBA\",\"kid\":\"AQI\",\"kty\":\"oct\"}]}", + GenerateJWKSet(data2, arraysize(data2), data1, arraysize(data1))); EXPECT_EQ( - "{\"keys\":[{\"alg\":\"A128KW\",\"k\":\"AQI\",\"kid\":\"AQIDBA\",\"kty\":" - "\"oct\"}]}", - GenerateJWKSet(data1, arraysize(data1), data2, arraysize(data2))); - EXPECT_EQ( - "{\"keys\":[{\"alg\":\"A128KW\",\"k\":\"AQIDBA\",\"kid\":\"AQI\",\"kty\":" - "\"oct\"}]}", - GenerateJWKSet(data2, arraysize(data2), data1, arraysize(data1))); - EXPECT_EQ( - "{\"keys\":[{\"alg\":\"A128KW\",\"k\":\"AQIDBAUGBwgJCgsMDQ4PEA\",\"kid\":" + "{\"keys\":[{\"k\":\"AQIDBAUGBwgJCgsMDQ4PEA\",\"kid\":" "\"AQIDBAUGBwgJCgsMDQ4PEA\",\"kty\":\"oct\"}]}", GenerateJWKSet(data3, arraysize(data3), data3, arraysize(data3))); } @@ -111,7 +104,6 @@ " \"keys\": [" " {" " \"kty\": \"oct\"," - " \"alg\": \"A128KW\"," " \"kid\": \"AAECAwQFBgcICQoLDA0ODxAREhM\"," " \"k\": \"FBUWFxgZGhscHR4fICEiIw\"" " }" @@ -125,13 +117,11 @@ " \"keys\": [" " {" " \"kty\": \"oct\"," - " \"alg\": \"A128KW\"," " \"kid\": \"AAECAwQFBgcICQoLDA0ODxAREhM\"," " \"k\": \"FBUWFxgZGhscHR4fICEiIw\"" " }," " {" " \"kty\": \"oct\"," - " \"alg\": \"A128KW\"," " \"kid\": \"JCUmJygpKissLS4vMA\"," " \"k\":\"MTIzNDU2Nzg5Ojs8PT4_QA\"" " }" @@ -141,7 +131,7 @@ // Try a key with no spaces and some \n plus additional fields. const std::string kJwksNoSpaces = - "\n\n{\"something\":1,\"keys\":[{\n\n\"kty\":\"oct\",\"alg\":\"A128KW\"," + "\n\n{\"something\":1,\"keys\":[{\n\n\"kty\":\"oct\"," "\"kid\":\"AAECAwQFBgcICQoLDA0ODxAREhM\",\"k\":\"GawgguFyGrWKav7AX4VKUg" "\",\"foo\":\"bar\"}]}\n\n"; ExtractJWKKeysAndExpect(kJwksNoSpaces, true, 1); @@ -152,13 +142,11 @@ " \"keys\": [" " {" " \"kty\": \"oct\"," - " \"alg\": \"A128KW\"," " \"kid\": \"JCUmJygpKissLS4vMA\"," " \"k\": \"FBUWFxgZGhscHR4fICEiIw\"" " }," " {" " \"kty\": \"oct\"," - " \"alg\": \"A128KW\"," " \"kid\": \"JCUmJygpKissLS4vMA\"," " \"k\":\"MTIzNDU2Nzg5Ojs8PT4_QA\"" " }" @@ -172,7 +160,6 @@ const std::string kJwkSimple = "{" " \"kty\": \"oct\"," - " \"alg\": \"A128KW\"," " \"kid\": \"AAECAwQFBgcICQoLDA0ODxAREhM\"," " \"k\": \"FBUWFxgZGhscHR4fICEiIw\"" "}"; @@ -184,7 +171,7 @@ // Try some non-ASCII characters in an otherwise valid JWK. const std::string kJwksInvalidCharacters = - "\n\n{\"something\":1,\"keys\":[{\n\n\"kty\":\"oct\",\"alg\":\"A128KW\"," + "\n\n{\"something\":1,\"keys\":[{\n\n\"kty\":\"oct\"," "\"kid\":\"AAECAwQFBgcICQoLDA0ODxAREhM\",\"k\":\"\xff\xfe\xfd" "\",\"foo\":\"bar\"}]}\n\n"; ExtractJWKKeysAndExpect(kJwksInvalidCharacters, false, 0); @@ -212,7 +199,6 @@ " \"keys\": [" " {" " \"kty\": \"oct\"," - " \"alg\": \"A128KW\"," " \"kid\": \"AAECAw\"," " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw==\"" " }" @@ -226,7 +212,6 @@ " \"keys\": [" " {" " \"kty\": \"oct\"," - " \"alg\": \"A128KW\"," " \"kid\": \"AAECAw==\"," " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\"" " }" @@ -240,7 +225,6 @@ " \"keys\": [" " {" " \"kty\": \"oct\"," - " \"alg\": \"A128KW\"," " \"kid\": \"!@#$%^&*()\"," " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\"" " }" @@ -254,7 +238,6 @@ " \"keys\": [" " {" " \"kty\": \"oct\"," - " \"alg\": \"A128KW\"," " \"kid\": \"\"," " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\"" " }" @@ -270,7 +253,6 @@ " \"keys\": [" " {" " \"kty\": \"oct\"," - " \"alg\": \"A128KW\"," " \"kid\": \"AAECAwQFBgcICQoLDA0ODxAREhM\"," " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\"" " }" @@ -284,7 +266,6 @@ " \"keys\": [" " {" " \"kty\": \"\"," - " \"alg\": \"A128KW\"," " \"kid\": \"AAECAwQFBgcICQoLDA0ODxAREhM\"," " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\"" " }" @@ -298,7 +279,6 @@ " \"keys\": [" " {" " \"kty\": \"OCT\"," - " \"alg\": \"A128KW\"," " \"kid\": \"AAECAwQFBgcICQoLDA0ODxAREhM\"," " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\"" " }" @@ -312,7 +292,6 @@ " \"keys\": [" " {" " \"kty\": \"RSA\"," - " \"alg\": \"A128KW\"," " \"kid\": \"AAECAwQFBgcICQoLDA0ODxAREhM\"," " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\"" " }" @@ -322,6 +301,7 @@ } TEST_F(JSONWebKeyTest, Alg) { + // 'alg' is ignored, so verify that anything is allowed. // Valid alg. const std::string kJwksWithValidAlg = "{" @@ -348,7 +328,7 @@ " }" " ]" "}"; - ExtractJWKKeysAndExpect(kJwksWithEmptyAlg, false, 0); + ExtractJWKKeysAndExpect(kJwksWithEmptyAlg, true, 1); // Alg is case sensitive. const std::string kJwksWithLowercaseAlg = @@ -362,7 +342,7 @@ " }" " ]" "}"; - ExtractJWKKeysAndExpect(kJwksWithLowercaseAlg, false, 0); + ExtractJWKKeysAndExpect(kJwksWithLowercaseAlg, true, 1); // Wrong alg. const std::string kJwksWithWrongAlg = @@ -376,37 +356,31 @@ " }" " ]" "}"; - ExtractJWKKeysAndExpect(kJwksWithWrongAlg, false, 0); + ExtractJWKKeysAndExpect(kJwksWithWrongAlg, true, 1); } TEST_F(JSONWebKeyTest, SessionType) { ExtractSessionTypeAndExpect( - "{\"keys\":[{\"alg\": " - "\"A128KW\",\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}]}", - true, MediaKeys::TEMPORARY_SESSION); + "{\"keys\":[{\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}]}", true, + MediaKeys::TEMPORARY_SESSION); ExtractSessionTypeAndExpect( - "{\"keys\":[{\"alg\": " - "\"A128KW\",\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}],\"type\":" + "{\"keys\":[{\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}],\"type\":" "\"temporary\"}", true, MediaKeys::TEMPORARY_SESSION); ExtractSessionTypeAndExpect( - "{\"keys\":[{\"alg\": " - "\"A128KW\",\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}],\"type\":" + "{\"keys\":[{\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}],\"type\":" "\"persistent-license\"}", true, MediaKeys::PERSISTENT_LICENSE_SESSION); ExtractSessionTypeAndExpect( - "{\"keys\":[{\"alg\": " - "\"A128KW\",\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}],\"type\":" + "{\"keys\":[{\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}],\"type\":" "\"persistent-release-message\"}", true, MediaKeys::PERSISTENT_RELEASE_MESSAGE_SESSION); ExtractSessionTypeAndExpect( - "{\"keys\":[{\"alg\": " - "\"A128KW\",\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}],\"type\":" + "{\"keys\":[{\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}],\"type\":" "\"unknown\"}", false, MediaKeys::TEMPORARY_SESSION); ExtractSessionTypeAndExpect( - "{\"keys\":[{\"alg\": " - "\"A128KW\",\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}],\"type\":3}", + "{\"keys\":[{\"k\":\"AQI\",\"kid\":\"AQI\",\"kty\":\"oct\"}],\"type\":3}", false, MediaKeys::TEMPORARY_SESSION); }
diff --git a/media/cdm/proxy_decryptor.cc b/media/cdm/proxy_decryptor.cc index 944b6140..9260e14 100644 --- a/media/cdm/proxy_decryptor.cc +++ b/media/cdm/proxy_decryptor.cc
@@ -25,11 +25,22 @@ // EME API. const int kSessionClosedSystemCode = 29127; +ProxyDecryptor::PendingGenerateKeyRequestData::PendingGenerateKeyRequestData( + EmeInitDataType init_data_type, + const std::vector<uint8>& init_data) + : init_data_type(init_data_type), init_data(init_data) { +} + +ProxyDecryptor::PendingGenerateKeyRequestData:: + ~PendingGenerateKeyRequestData() { +} + ProxyDecryptor::ProxyDecryptor(MediaPermission* media_permission, const KeyAddedCB& key_added_cb, const KeyErrorCB& key_error_cb, const KeyMessageCB& key_message_cb) - : media_permission_(media_permission), + : is_creating_cdm_(false), + media_permission_(media_permission), key_added_cb_(key_added_cb), key_error_cb_(key_error_cb), key_message_cb_(key_message_cb), @@ -46,33 +57,77 @@ media_keys_.reset(); } -CdmContext* ProxyDecryptor::GetCdmContext() { - return media_keys_ ? media_keys_->GetCdmContext() : nullptr; +void ProxyDecryptor::CreateCdm(CdmFactory* cdm_factory, + const std::string& key_system, + const GURL& security_origin, + const CdmContextReadyCB& cdm_context_ready_cb) { + DVLOG(1) << __FUNCTION__ << ": key_system = " << key_system; + DCHECK(!is_creating_cdm_); + DCHECK(!media_keys_); + + // TODO(sandersd): Trigger permissions check here and use it to determine + // distinctive identifier support, instead of always requiring the + // permission. http://crbug.com/455271 + bool allow_distinctive_identifier = true; + bool allow_persistent_state = true; + + is_creating_cdm_ = true; + + base::WeakPtr<ProxyDecryptor> weak_this = weak_ptr_factory_.GetWeakPtr(); + cdm_factory->Create( + key_system, allow_distinctive_identifier, allow_persistent_state, + security_origin, base::Bind(&ProxyDecryptor::OnSessionMessage, weak_this), + base::Bind(&ProxyDecryptor::OnSessionClosed, weak_this), + base::Bind(&ProxyDecryptor::OnLegacySessionError, weak_this), + base::Bind(&ProxyDecryptor::OnSessionKeysChange, weak_this), + base::Bind(&ProxyDecryptor::OnSessionExpirationUpdate, weak_this), + base::Bind(&ProxyDecryptor::OnCdmCreated, weak_this, key_system, + security_origin, cdm_context_ready_cb)); } -bool ProxyDecryptor::InitializeCDM(CdmFactory* cdm_factory, - const std::string& key_system, - const GURL& security_origin) { - DVLOG(1) << "InitializeCDM: key_system = " << key_system; +void ProxyDecryptor::OnCdmCreated(const std::string& key_system, + const GURL& security_origin, + const CdmContextReadyCB& cdm_context_ready_cb, + scoped_ptr<MediaKeys> cdm) { + is_creating_cdm_ = false; - DCHECK(!media_keys_); - media_keys_ = CreateMediaKeys(cdm_factory, key_system, security_origin); - if (!media_keys_) - return false; + if (!cdm) { + cdm_context_ready_cb.Run(nullptr); + return; + } key_system_ = key_system; security_origin_ = security_origin; + is_clear_key_ = IsClearKey(key_system) || IsExternalClearKey(key_system); + media_keys_ = cdm.Pass(); - is_clear_key_ = - IsClearKey(key_system) || IsExternalClearKey(key_system); - return true; + cdm_context_ready_cb.Run(media_keys_->GetCdmContext()); + + for (const auto& request : pending_requests_) + GenerateKeyRequestInternal(request->init_data_type, request->init_data); + + pending_requests_.clear(); +} + +void ProxyDecryptor::GenerateKeyRequest(EmeInitDataType init_data_type, + const uint8* init_data, + int init_data_length) { + std::vector<uint8> init_data_vector(init_data, init_data + init_data_length); + + if (is_creating_cdm_) { + pending_requests_.push_back( + new PendingGenerateKeyRequestData(init_data_type, init_data_vector)); + return; + } + + GenerateKeyRequestInternal(init_data_type, init_data_vector); } // Returns true if |data| is prefixed with |header| and has data after the // |header|. -bool HasHeader(const uint8* data, int data_length, const std::string& header) { - return static_cast<size_t>(data_length) > header.size() && - std::equal(data, data + header.size(), header.begin()); +bool HasHeader(const std::vector<uint8>& data, const std::string& header) { + return data.size() > header.size() && + std::equal(header.begin(), header.end(), data.begin()); } // Removes the first |length| items from |data|. @@ -80,23 +135,30 @@ data.erase(data.begin(), data.begin() + length); } -bool ProxyDecryptor::GenerateKeyRequest(EmeInitDataType init_data_type, - const uint8* init_data, - int init_data_length) { - DVLOG(1) << "GenerateKeyRequest()"; +void ProxyDecryptor::GenerateKeyRequestInternal( + EmeInitDataType init_data_type, + const std::vector<uint8>& init_data) { + DVLOG(1) << __FUNCTION__; + DCHECK(!is_creating_cdm_); + + if (!media_keys_) { + OnLegacySessionError(std::string(), MediaKeys::NOT_SUPPORTED_ERROR, 0, + "CDM creation failed."); + return; + } + const char kPrefixedApiPersistentSessionHeader[] = "PERSISTENT|"; const char kPrefixedApiLoadSessionHeader[] = "LOAD_SESSION|"; SessionCreationType session_creation_type = TemporarySession; - std::vector<uint8> init_data_vector(init_data, init_data + init_data_length); - if (HasHeader(init_data, init_data_length, kPrefixedApiLoadSessionHeader)) { + std::vector<uint8> stripped_init_data = init_data; + if (HasHeader(init_data, kPrefixedApiLoadSessionHeader)) { session_creation_type = LoadSession; - StripHeader(init_data_vector, strlen(kPrefixedApiLoadSessionHeader)); - } else if (HasHeader(init_data, - init_data_length, - kPrefixedApiPersistentSessionHeader)) { + StripHeader(stripped_init_data, strlen(kPrefixedApiLoadSessionHeader)); + } else if (HasHeader(init_data, kPrefixedApiPersistentSessionHeader)) { session_creation_type = PersistentSession; - StripHeader(init_data_vector, strlen(kPrefixedApiPersistentSessionHeader)); + StripHeader(stripped_init_data, + strlen(kPrefixedApiPersistentSessionHeader)); } scoped_ptr<NewSessionCdmPromise> promise(new CdmCallbackPromise<std::string>( @@ -110,10 +172,10 @@ media_keys_->LoadSession( MediaKeys::PERSISTENT_LICENSE_SESSION, std::string( - reinterpret_cast<const char*>(vector_as_array(&init_data_vector)), - init_data_vector.size()), + reinterpret_cast<const char*>(vector_as_array(&stripped_init_data)), + stripped_init_data.size()), promise.Pass()); - return true; + return; } MediaKeys::SessionType session_type = @@ -125,9 +187,9 @@ // external clear key. DCHECK(!key_system_.empty()); if (CanUseAesDecryptor(key_system_) || IsExternalClearKey(key_system_)) { - OnPermissionStatus(session_type, init_data_type, init_data_vector, + OnPermissionStatus(session_type, init_data_type, stripped_init_data, promise.Pass(), true /* granted */); - return true; + return; } #if defined(OS_CHROMEOS) || defined(OS_ANDROID) @@ -135,13 +197,11 @@ MediaPermission::PROTECTED_MEDIA_IDENTIFIER, security_origin_, base::Bind(&ProxyDecryptor::OnPermissionStatus, weak_ptr_factory_.GetWeakPtr(), session_type, init_data_type, - init_data_vector, base::Passed(&promise))); + stripped_init_data, base::Passed(&promise))); #else - OnPermissionStatus(session_type, init_data_type, init_data_vector, + OnPermissionStatus(session_type, init_data_type, stripped_init_data, promise.Pass(), true /* granted */); #endif - - return true; } void ProxyDecryptor::OnPermissionStatus( @@ -168,6 +228,12 @@ const std::string& session_id) { DVLOG(1) << "AddKey()"; + if (!media_keys_) { + OnLegacySessionError(std::string(), MediaKeys::INVALID_STATE_ERROR, 0, + "CDM is not available."); + return; + } + // In the prefixed API, the session parameter provided to addKey() is // optional, so use the single existing session if it exists. std::string new_session_id(session_id); @@ -216,6 +282,12 @@ void ProxyDecryptor::CancelKeyRequest(const std::string& session_id) { DVLOG(1) << "CancelKeyRequest()"; + if (!media_keys_) { + OnLegacySessionError(std::string(), MediaKeys::INVALID_STATE_ERROR, 0, + "CDM is not available."); + return; + } + scoped_ptr<SimpleCdmPromise> promise(new CdmCallbackPromise<>( base::Bind(&ProxyDecryptor::OnSessionClosed, weak_ptr_factory_.GetWeakPtr(), session_id), @@ -224,25 +296,6 @@ media_keys_->RemoveSession(session_id, promise.Pass()); } -scoped_ptr<MediaKeys> ProxyDecryptor::CreateMediaKeys( - CdmFactory* cdm_factory, - const std::string& key_system, - const GURL& security_origin) { - // TODO(sandersd): Trigger permissions check here and use it to determine - // distinctive identifier support, instead of always requiring the - // permission. http://crbug.com/455271 - bool allow_distinctive_identifier = true; - bool allow_persistent_state = true; - base::WeakPtr<ProxyDecryptor> weak_this = weak_ptr_factory_.GetWeakPtr(); - return cdm_factory->Create( - key_system, allow_distinctive_identifier, allow_persistent_state, - security_origin, base::Bind(&ProxyDecryptor::OnSessionMessage, weak_this), - base::Bind(&ProxyDecryptor::OnSessionClosed, weak_this), - base::Bind(&ProxyDecryptor::OnLegacySessionError, weak_this), - base::Bind(&ProxyDecryptor::OnSessionKeysChange, weak_this), - base::Bind(&ProxyDecryptor::OnSessionExpirationUpdate, weak_this)); -} - void ProxyDecryptor::OnSessionMessage(const std::string& session_id, MediaKeys::MessageType message_type, const std::vector<uint8>& message,
diff --git a/media/cdm/proxy_decryptor.h b/media/cdm/proxy_decryptor.h index ff611ad..9a17a98c 100644 --- a/media/cdm/proxy_decryptor.h +++ b/media/cdm/proxy_decryptor.h
@@ -11,7 +11,9 @@ #include "base/basictypes.h" #include "base/containers/hash_tables.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/scoped_vector.h" #include "base/memory/weak_ptr.h" +#include "media/base/cdm_context.h" #include "media/base/decryptor.h" #include "media/base/eme_constants.h" #include "media/base/media_export.h" @@ -32,6 +34,10 @@ // TODO(xhwang): The ProxyDecryptor is not a Decryptor. Find a better name! class MEDIA_EXPORT ProxyDecryptor { public: + // Callback to provide a CdmContext when the CDM creation is finished. + // If CDM creation failed, |cdm_context| will be null. + typedef base::Callback<void(CdmContext* cdm_context)> CdmContextReadyCB; + // These are similar to the callbacks in media_keys.h, but pass back the // session ID rather than the internal session ID. typedef base::Callback<void(const std::string& session_id)> KeyAddedCB; @@ -48,16 +54,16 @@ const KeyMessageCB& key_message_cb); virtual ~ProxyDecryptor(); - // Returns the CdmContext associated with this object. - CdmContext* GetCdmContext(); + // Creates the CDM and fires |cdm_created_cb|. This method should only be + // called once. If CDM creation failed, all following GenerateKeyRequest, + // AddKey and CancelKeyRequest calls will result in a KeyError. + void CreateCdm(CdmFactory* cdm_factory, + const std::string& key_system, + const GURL& security_origin, + const CdmContextReadyCB& cdm_context_ready_cb); - // Only call this once. - bool InitializeCDM(CdmFactory* cdm_factory, - const std::string& key_system, - const GURL& security_origin); - - // May only be called after InitializeCDM() succeeds. - bool GenerateKeyRequest(EmeInitDataType init_data_type, + // May only be called after CreateCDM(). + void GenerateKeyRequest(EmeInitDataType init_data_type, const uint8* init_data, int init_data_length); void AddKey(const uint8* key, int key_length, @@ -66,11 +72,14 @@ void CancelKeyRequest(const std::string& session_id); private: - // Helper function to create MediaKeys to handle the given |key_system|. - scoped_ptr<MediaKeys> CreateMediaKeys( - CdmFactory* cdm_factory, - const std::string& key_system, - const GURL& security_origin); + // Callback for CreateCdm(). + void OnCdmCreated(const std::string& key_system, + const GURL& security_origin, + const CdmContextReadyCB& cdm_context_ready_cb, + scoped_ptr<MediaKeys> cdm); + + void GenerateKeyRequestInternal(EmeInitDataType init_data_type, + const std::vector<uint8>& init_data); // Callbacks for firing session events. void OnSessionMessage(const std::string& session_id, @@ -106,6 +115,17 @@ void SetSessionId(SessionCreationType session_type, const std::string& session_id); + struct PendingGenerateKeyRequestData { + PendingGenerateKeyRequestData(EmeInitDataType init_data_type, + const std::vector<uint8>& init_data); + ~PendingGenerateKeyRequestData(); + + const EmeInitDataType init_data_type; + const std::vector<uint8> init_data; + }; + + bool is_creating_cdm_; + // The real MediaKeys that manages key operations for the ProxyDecryptor. scoped_ptr<MediaKeys> media_keys_; @@ -124,6 +144,8 @@ bool is_clear_key_; + ScopedVector<PendingGenerateKeyRequestData> pending_requests_; + // NOTE: Weak pointers must be invalidated before all other member variables. base::WeakPtrFactory<ProxyDecryptor> weak_ptr_factory_;
diff --git a/mojo/application/BUILD.gn b/mojo/application/BUILD.gn index e6b50dc..22c91af1 100644 --- a/mojo/application/BUILD.gn +++ b/mojo/application/BUILD.gn
@@ -38,14 +38,18 @@ source_set("test_support") { testonly = true sources = [ + "application_test_base_chromium.cc", + "application_test_base_chromium.h", "application_test_main_chromium.cc", ] - public_deps = [ - "//third_party/mojo/src/mojo/public/cpp/application:test_support", - ] deps = [ "//base", "//base/test:test_support", + "//third_party/mojo/src/mojo/public/cpp/application:application", + "//third_party/mojo/src/mojo/public/cpp/bindings", + "//third_party/mojo/src/mojo/public/cpp/environment", + "//third_party/mojo/src/mojo/public/cpp/system", + "//testing/gtest", ] }
diff --git a/mojo/application/application_runner_chromium.cc b/mojo/application/application_runner_chromium.cc index 069ff90..e5f21caa 100644 --- a/mojo/application/application_runner_chromium.cc +++ b/mojo/application/application_runner_chromium.cc
@@ -13,6 +13,18 @@ #include "mojo/public/cpp/application/application_delegate.h" #include "mojo/public/cpp/application/application_impl.h" +int g_argc; +const char* const* g_argv; +#if !defined(OS_WIN) +extern "C" { +__attribute__((visibility("default"))) void InitCommandLineArgs( + int argc, const char* const* argv) { + g_argc = argc; + g_argv = argv; +} +} +#endif + namespace mojo { // static @@ -29,6 +41,10 @@ ApplicationRunnerChromium::~ApplicationRunnerChromium() {} +void ApplicationRunnerChromium::InitBaseCommandLine() { + base::CommandLine::Init(g_argc, g_argv); +} + void ApplicationRunnerChromium::set_message_loop_type( base::MessageLoop::Type type) { DCHECK_NE(base::MessageLoop::TYPE_CUSTOM, type); @@ -42,7 +58,7 @@ DCHECK(!has_run_); has_run_ = true; - base::CommandLine::Init(0, NULL); + InitBaseCommandLine(); base::AtExitManager at_exit; #ifndef NDEBUG
diff --git a/mojo/application/application_runner_chromium.h b/mojo/application/application_runner_chromium.h index cb586850..2d6d910 100644 --- a/mojo/application/application_runner_chromium.h +++ b/mojo/application/application_runner_chromium.h
@@ -30,6 +30,8 @@ explicit ApplicationRunnerChromium(ApplicationDelegate* delegate); ~ApplicationRunnerChromium(); + static void InitBaseCommandLine(); + void set_message_loop_type(base::MessageLoop::Type type); // Once the various parameters have been set above, use Run to initialize an
diff --git a/mojo/application/application_test_base_chromium.cc b/mojo/application/application_test_base_chromium.cc new file mode 100644 index 0000000..4d74f4f2 --- /dev/null +++ b/mojo/application/application_test_base_chromium.cc
@@ -0,0 +1,150 @@ +// 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 "mojo/application/application_test_base_chromium.h" + +#include "base/command_line.h" +#include "base/strings/utf_string_conversions.h" +#include "mojo/public/cpp/application/application_impl.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/environment/environment.h" +#include "mojo/public/cpp/system/message_pipe.h" +#include "mojo/public/interfaces/application/application.mojom.h" + +namespace mojo { +namespace test { + +namespace { +// Share the application URL with multiple application tests. +String g_url; + +// Application request handle passed from the shell in MojoMain, stored in +// between SetUp()/TearDown() so we can (re-)intialize new ApplicationImpls. +InterfaceRequest<Application> g_application_request; + +// Shell pointer passed in the initial mojo.Application.Initialize() call, +// stored in between initial setup and the first test and between SetUp/TearDown +// calls so we can (re-)initialize new ApplicationImpls. +ShellPtr g_shell; + +class ShellGrabber : public Application { + public: + explicit ShellGrabber(InterfaceRequest<Application> application_request) + : binding_(this, application_request.Pass()) {} + + void WaitForInitialize() { + // Initialize is always the first call made on Application. + MOJO_CHECK(binding_.WaitForIncomingMethodCall()); + } + + private: + // Application implementation. + void Initialize(ShellPtr shell, + Array<String> args, + const mojo::String& url) override { + g_url = url; + g_application_request = binding_.Unbind(); + g_shell = shell.Pass(); + } + + void AcceptConnection(const String& requestor_url, + InterfaceRequest<ServiceProvider> services, + ServiceProviderPtr exposed_services, + const String& url) override { + MOJO_CHECK(false); + } + + void RequestQuit() override { MOJO_CHECK(false); } + + Binding<Application> binding_; +}; + +} // namespace + +MojoResult RunAllTests(MojoHandle application_request_handle) { + { + // This loop is used for init, and then destroyed before running tests. + Environment::InstantiateDefaultRunLoop(); + + // Grab the shell handle. + ShellGrabber grabber( + MakeRequest<Application>(MakeScopedHandle( + MessagePipeHandle(application_request_handle)))); + grabber.WaitForInitialize(); + MOJO_CHECK(g_shell); + MOJO_CHECK(g_application_request.is_pending()); + + int argc = 0; + base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); + const char** argv = new const char* [cmd_line->argv().size()]; +#if defined(OS_WIN) + std::vector<std::string> local_strings; +#endif + for (auto& arg : cmd_line->argv()) { +#if defined(OS_WIN) + local_strings.push_back(base::WideToUTF8(arg)); + argv[argc++] = local_strings.back().c_str(); +#else + argv[argc++] = arg.c_str(); +#endif + } + + testing::InitGoogleTest(&argc, const_cast<char**>(&(argv[0]))); + + Environment::DestroyDefaultRunLoop(); + } + + int result = RUN_ALL_TESTS(); + + // Shut down our message pipes before exiting. + (void)g_application_request.PassMessagePipe(); + (void)g_shell.PassMessagePipe(); + + return (result == 0) ? MOJO_RESULT_OK : MOJO_RESULT_UNKNOWN; +} + +ApplicationTestBase::ApplicationTestBase() : application_impl_(nullptr) { +} + +ApplicationTestBase::~ApplicationTestBase() { +} + +ApplicationDelegate* ApplicationTestBase::GetApplicationDelegate() { + return &default_application_delegate_; +} + +void ApplicationTestBase::SetUp() { + // A run loop is recommended for ApplicationImpl initialization and + // communication. + if (ShouldCreateDefaultRunLoop()) + Environment::InstantiateDefaultRunLoop(); + + MOJO_CHECK(g_application_request.is_pending()); + MOJO_CHECK(g_shell); + + // New applications are constructed for each test to avoid persisting state. + application_impl_ = new ApplicationImpl(GetApplicationDelegate(), + g_application_request.Pass()); + + // Fake application initialization with the given command line arguments. + Array<String> empty_args; + application_impl_->Initialize(g_shell.Pass(), empty_args.Clone(), g_url); +} + +void ApplicationTestBase::TearDown() { + MOJO_CHECK(!g_application_request.is_pending()); + MOJO_CHECK(!g_shell); + + application_impl_->UnbindConnections(&g_application_request, &g_shell); + delete application_impl_; + if (ShouldCreateDefaultRunLoop()) + Environment::DestroyDefaultRunLoop(); +} + +bool ApplicationTestBase::ShouldCreateDefaultRunLoop() { + return true; +} + +} // namespace test +} // namespace mojo
diff --git a/mojo/application/application_test_base_chromium.h b/mojo/application/application_test_base_chromium.h new file mode 100644 index 0000000..c050848 --- /dev/null +++ b/mojo/application/application_test_base_chromium.h
@@ -0,0 +1,59 @@ +// 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 MOJO_APPLICATION_APPLICATION_TEST_BASE_CHROMIUM_H_ +#define MOJO_APPLICATION_APPLICATION_TEST_BASE_CHROMIUM_H_ + +#include "mojo/public/cpp/application/application_delegate.h" +#include "mojo/public/cpp/bindings/array.h" +#include "mojo/public/cpp/bindings/string.h" +#include "mojo/public/cpp/system/macros.h" +#include "mojo/public/interfaces/application/application.mojom.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace mojo { + +class ApplicationImpl; + +namespace test { + +// Run all application tests. This must be called after the environment is +// initialized, to support construction of a default run loop. +MojoResult RunAllTests(MojoHandle application_request_handle); + +// A GTEST base class for application testing executed in mojo_shell. +class ApplicationTestBase : public testing::Test { + public: + ApplicationTestBase(); + ~ApplicationTestBase() override; + + protected: + ApplicationImpl* application_impl() { return application_impl_; } + + // Get the ApplicationDelegate for the application to be tested. + virtual ApplicationDelegate* GetApplicationDelegate(); + + // testing::Test: + void SetUp() override; + void TearDown() override; + + // True by default, which indicates a MessageLoop will automatically be + // created for the application. Tests may override this function to prevent + // a default loop from being created. + virtual bool ShouldCreateDefaultRunLoop(); + + private: + // The application implementation instance, reconstructed for each test. + ApplicationImpl* application_impl_; + // The application delegate used if GetApplicationDelegate is not overridden. + ApplicationDelegate default_application_delegate_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(ApplicationTestBase); +}; + +} // namespace test + +} // namespace mojo + +#endif // MOJO_APPLICATION_APPLICATION_TEST_BASE_CHROMIUM_H_
diff --git a/mojo/application/application_test_main_chromium.cc b/mojo/application/application_test_main_chromium.cc index 4ce761a8..3d6c4b2 100644 --- a/mojo/application/application_test_main_chromium.cc +++ b/mojo/application/application_test_main_chromium.cc
@@ -5,8 +5,9 @@ #include "base/at_exit.h" #include "base/command_line.h" #include "base/test/test_timeouts.h" +#include "mojo/application/application_runner_chromium.h" +#include "mojo/application/application_test_base_chromium.h" #include "mojo/public/c/system/main.h" -#include "mojo/public/cpp/application/application_test_base.h" MojoResult MojoMain(MojoHandle handle) { // An AtExitManager instance is needed to construct message loops. @@ -14,7 +15,7 @@ // Initialize test timeouts, which requires CommandLine::ForCurrentProcess(). // TODO(msw): Plumb relevant command line args before initializing timeouts. - base::CommandLine::Init(0, nullptr); + mojo::ApplicationRunnerChromium::InitBaseCommandLine(); TestTimeouts::Initialize(); return mojo::test::RunAllTests(handle);
diff --git a/mojo/services/BUILD.gn b/mojo/services/BUILD.gn index bc6256df..945e6f05 100644 --- a/mojo/services/BUILD.gn +++ b/mojo/services/BUILD.gn
@@ -21,7 +21,7 @@ deps += [ "//mojo/services/clipboard", "//mojo/services/html_viewer", - "//mojo/services/kiosk_wm", + "//mojo/services/kiosk_wm:window_manager", "//mojo/services/native_viewport", "//mojo/services/network", "//mojo/services/surfaces", @@ -33,7 +33,7 @@ if (is_mac) { deps -= [ "//mojo/services/html_viewer", - "//mojo/services/kiosk_wm", + "//mojo/services/kiosk_wm:window_manager", "//mojo/services/native_viewport", "//mojo/services/view_manager", ]
diff --git a/mojo/services/clipboard/clipboard_apptest.cc b/mojo/services/clipboard/clipboard_apptest.cc index b6a2fad..cb8f1e6 100644 --- a/mojo/services/clipboard/clipboard_apptest.cc +++ b/mojo/services/clipboard/clipboard_apptest.cc
@@ -4,9 +4,9 @@ #include "base/bind.h" #include "base/run_loop.h" +#include "mojo/application/application_test_base_chromium.h" #include "mojo/common/common_type_converters.h" #include "mojo/public/cpp/application/application_impl.h" -#include "mojo/public/cpp/application/application_test_base.h" #include "third_party/mojo_services/src/clipboard/public/interfaces/clipboard.mojom.h" using mojo::Array;
diff --git a/mojo/services/html_viewer/ax_provider_apptest.cc b/mojo/services/html_viewer/ax_provider_apptest.cc index 29dc501..576b89a 100644 --- a/mojo/services/html_viewer/ax_provider_apptest.cc +++ b/mojo/services/html_viewer/ax_provider_apptest.cc
@@ -6,8 +6,8 @@ #include "base/run_loop.h" #include "base/strings/stringprintf.h" #include "base/test/test_timeouts.h" +#include "mojo/application/application_test_base_chromium.h" #include "mojo/public/cpp/application/application_impl.h" -#include "mojo/public/cpp/application/application_test_base.h" #include "net/test/spawned_test_server/spawned_test_server.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/mojo_services/src/accessibility/public/interfaces/accessibility.mojom.h"
diff --git a/mojo/services/html_viewer/html_viewer.cc b/mojo/services/html_viewer/html_viewer.cc index abe6379a..201343c 100644 --- a/mojo/services/html_viewer/html_viewer.cc +++ b/mojo/services/html_viewer/html_viewer.cc
@@ -44,8 +44,7 @@ namespace html_viewer { -// Switches for html_viewer to be used with "--args-for". For example: -// --args-for='mojo:html_viewer --enable-mojo-media-renderer' +// Switches for html_viewer. // Enable MediaRenderer in media pipeline instead of using the internal // media::Renderer implementation. @@ -183,16 +182,7 @@ ui::RegisterPathProvider(); - base::CommandLine::StringVector command_line_args; -#if defined(OS_WIN) - for (const auto& arg : app->args()) - command_line_args.push_back(base::UTF8ToUTF16(arg)); -#elif defined(OS_POSIX) - command_line_args = app->args(); -#endif - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - command_line->InitFromArgv(command_line_args); logging::LoggingSettings settings; settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
diff --git a/mojo/services/html_viewer/view_url.py b/mojo/services/html_viewer/view_url.py deleted file mode 100755 index a543385..0000000 --- a/mojo/services/html_viewer/view_url.py +++ /dev/null
@@ -1,57 +0,0 @@ -#!/usr/bin/env python -# 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 argparse -import os -import subprocess -import sys - -root_path = os.path.realpath( - os.path.join( - os.path.dirname( - os.path.realpath(__file__)), - os.pardir, - os.pardir, - os.pardir)) - -def _BuildShellCommand(args): - sdk_version = subprocess.check_output(["cat", - "third_party/mojo/src/mojo/public/VERSION"], cwd=root_path) - build_dir = os.path.join(root_path, args.build_dir) - - shell_command = [os.path.join(build_dir, "mojo_shell")] - - options = [] - options.append( - "--origin=https://storage.googleapis.com/mojo/services/linux-x64/%s" % - sdk_version) - options.append("--url-mappings=mojo:html_viewer=file://%s/html_viewer.mojo" % - build_dir) - options.append('--args-for=mojo:kiosk_wm %s' % args.url) - - app_to_run = "mojo:kiosk_wm" - - return shell_command + options + [app_to_run] - -def main(): - parser = argparse.ArgumentParser( - description="View a URL with HTMLViewer in the Kiosk window manager. " - "You must have built //mojo/services/html_viewer and " - "//mojo/services/network first. Note that this will " - "currently often fail spectacularly due to lack of binary " - "stability in Mojo.") - parser.add_argument( - "--build-dir", - help="Path to the dir containing the linux-x64 binaries relative to the " - "repo root (default: %(default)s)", - default="out/Release") - parser.add_argument("url", - help="The URL to be viewed") - - args = parser.parse_args() - return subprocess.call(_BuildShellCommand(args)) - -if __name__ == '__main__': - sys.exit(main())
diff --git a/mojo/services/kiosk_wm/BUILD.gn b/mojo/services/kiosk_wm/BUILD.gn index 99c25f0d..988c6c9 100644 --- a/mojo/services/kiosk_wm/BUILD.gn +++ b/mojo/services/kiosk_wm/BUILD.gn
@@ -5,7 +5,10 @@ import("//third_party/mojo/src/mojo/public/mojo_application.gni") import("$mojo_sdk_root/mojo/public/tools/bindings/mojom.gni") -mojo_native_application("kiosk_wm") { +# Mojo shell in chromium is only used for Mandoline, and Mandoline only uses +# kiosk_wm, so we name the target window_manager to avoid having to remap on the +# command line. +mojo_native_application("window_manager") { sources = [ "kiosk_wm.cc", "kiosk_wm.h",
diff --git a/mojo/services/kiosk_wm/kiosk_wm.cc b/mojo/services/kiosk_wm/kiosk_wm.cc index 444003a..5c03ade 100644 --- a/mojo/services/kiosk_wm/kiosk_wm.cc +++ b/mojo/services/kiosk_wm/kiosk_wm.cc
@@ -4,6 +4,8 @@ #include "mojo/services/kiosk_wm/kiosk_wm.h" +#include "base/command_line.h" +#include "base/strings/utf_string_conversions.h" #include "mojo/services/kiosk_wm/merged_service_provider.h" #include "mojo/services/window_manager/basic_focus_rules.h" @@ -28,9 +30,17 @@ void KioskWM::Initialize(mojo::ApplicationImpl* app) { window_manager_app_->Initialize(app); - // Format: --args-for="app_url default_url" - if (app->args().size() > 1) - default_url_ = app->args()[1]; + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + base::CommandLine::StringVector args = command_line->GetArgs(); + if (args.empty()) { + default_url_ = "http://www.google.com/"; + } else { +#if defined(OS_WIN) + default_url_ = base::WideToUTF8(args[0]); +#else + default_url_ = args[0]; +#endif + } } bool KioskWM::ConfigureIncomingConnection(
diff --git a/mojo/services/network/tcp_bound_socket_impl.cc b/mojo/services/network/tcp_bound_socket_impl.cc index 8272b22..b7763045 100644 --- a/mojo/services/network/tcp_bound_socket_impl.cc +++ b/mojo/services/network/tcp_bound_socket_impl.cc
@@ -104,11 +104,9 @@ void TCPBoundSocketImpl::OnConnected(int result) { if (result == net::OK) { - BindToRequest(new TCPConnectedSocketImpl( - socket_.Pass(), - pending_connect_send_stream_.Pass(), - pending_connect_receive_stream_.Pass()), - &pending_connect_socket_); + new TCPConnectedSocketImpl( + socket_.Pass(), pending_connect_send_stream_.Pass(), + pending_connect_receive_stream_.Pass(), pending_connect_socket_.Pass()); } else { pending_connect_send_stream_.reset(); pending_connect_receive_stream_.reset();
diff --git a/mojo/services/network/tcp_connected_socket_impl.cc b/mojo/services/network/tcp_connected_socket_impl.cc index 641f1c3..bc8c98b5 100644 --- a/mojo/services/network/tcp_connected_socket_impl.cc +++ b/mojo/services/network/tcp_connected_socket_impl.cc
@@ -13,12 +13,17 @@ TCPConnectedSocketImpl::TCPConnectedSocketImpl( scoped_ptr<net::TCPSocket> socket, ScopedDataPipeConsumerHandle send_stream, - ScopedDataPipeProducerHandle receive_stream) + ScopedDataPipeProducerHandle receive_stream, + InterfaceRequest<TCPConnectedSocket> request) : socket_(socket.Pass()), send_stream_(send_stream.Pass()), receive_stream_(receive_stream.Pass()), + binding_(this, request.Pass()), weak_ptr_factory_(this) { // Queue up async communication. + binding_.set_error_handler(this); + ListenForReceivePeerClosed(); + ListenForSendPeerClosed(); ReceiveMore(); SendMore(); } @@ -26,6 +31,11 @@ TCPConnectedSocketImpl::~TCPConnectedSocketImpl() { } +void TCPConnectedSocketImpl::OnConnectionError() { + binding_.Close(); + DeleteIfNeeded(); +} + void TCPConnectedSocketImpl::ReceiveMore() { DCHECK(!pending_receive_.get()); @@ -35,8 +45,7 @@ if (result == MOJO_RESULT_SHOULD_WAIT) { // The pipe is full. We need to wait for it to have more space. receive_handle_watcher_.Start( - receive_stream_.get(), - MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + receive_stream_.get(), MOJO_HANDLE_SIGNAL_WRITABLE, MOJO_DEADLINE_INDEFINITE, base::Bind(&TCPConnectedSocketImpl::OnReceiveStreamReady, weak_ptr_factory_.GetWeakPtr())); @@ -65,10 +74,10 @@ CHECK_GT(static_cast<uint32_t>(std::numeric_limits<int>::max()), num_bytes); scoped_refptr<net::IOBuffer> buf( new NetToMojoIOBuffer(pending_receive_.get())); - int read_result = socket_->Read( - buf.get(), static_cast<int>(num_bytes), - base::Bind(&TCPConnectedSocketImpl::DidReceive, base::Unretained(this), - false)); + int read_result = + socket_->Read(buf.get(), static_cast<int>(num_bytes), + base::Bind(&TCPConnectedSocketImpl::DidReceive, + weak_ptr_factory_.GetWeakPtr(), false)); if (read_result == net::ERR_IO_PENDING) { // Pending I/O, wait for result in DidReceive(). } else if (read_result > 0) { @@ -90,11 +99,15 @@ // net_result and mojo_result. return; } + ListenForReceivePeerClosed(); ReceiveMore(); } void TCPConnectedSocketImpl::DidReceive(bool completed_synchronously, int result) { + if (!pending_receive_) + return; + if (result < 0) { // Error. ShutdownReceive(); @@ -110,17 +123,30 @@ if (completed_synchronously) { // Don't recursively call ReceiveMore if this is a sync read. base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&TCPConnectedSocketImpl::ReceiveMore, - weak_ptr_factory_.GetWeakPtr())); + FROM_HERE, base::Bind(&TCPConnectedSocketImpl::ReceiveMore, + weak_ptr_factory_.GetWeakPtr())); } else { ReceiveMore(); } } void TCPConnectedSocketImpl::ShutdownReceive() { + receive_handle_watcher_.Stop(); pending_receive_ = nullptr; receive_stream_.reset(); + DeleteIfNeeded(); +} + +void TCPConnectedSocketImpl::ListenForReceivePeerClosed() { + receive_handle_watcher_.Start( + receive_stream_.get(), MOJO_HANDLE_SIGNAL_PEER_CLOSED, + MOJO_DEADLINE_INDEFINITE, + base::Bind(&TCPConnectedSocketImpl::OnReceiveDataPipeClosed, + weak_ptr_factory_.GetWeakPtr())); +} + +void TCPConnectedSocketImpl::OnReceiveDataPipeClosed(MojoResult result) { + ShutdownReceive(); } void TCPConnectedSocketImpl::SendMore() { @@ -130,8 +156,7 @@ if (result == MOJO_RESULT_SHOULD_WAIT) { // Data not ready, wait for it. send_handle_watcher_.Start( - send_stream_.get(), - MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + send_stream_.get(), MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE, base::Bind(&TCPConnectedSocketImpl::OnSendStreamReady, weak_ptr_factory_.GetWeakPtr())); @@ -146,10 +171,10 @@ // Got a buffer from Mojo, give it to the socket. Note that the sockets may // do partial writes. scoped_refptr<net::IOBuffer> buf(new MojoToNetIOBuffer(pending_send_.get())); - int write_result = socket_->Write( - buf.get(), static_cast<int>(num_bytes), - base::Bind(&TCPConnectedSocketImpl::DidSend, base::Unretained(this), - false)); + int write_result = + socket_->Write(buf.get(), static_cast<int>(num_bytes), + base::Bind(&TCPConnectedSocketImpl::DidSend, + weak_ptr_factory_.GetWeakPtr(), false)); if (write_result == net::ERR_IO_PENDING) { // Pending I/O, wait for result in DidSend(). } else if (write_result >= 0) { @@ -170,11 +195,14 @@ // net_result and mojo_result. return; } + ListenForSendPeerClosed(); SendMore(); } -void TCPConnectedSocketImpl::DidSend(bool completed_synchronously, - int result) { +void TCPConnectedSocketImpl::DidSend(bool completed_synchronously, int result) { + if (!pending_send_) + return; + if (result < 0) { ShutdownSend(); // TODO(johnmccutchan): Notify socket direction is closed along with @@ -190,17 +218,37 @@ if (completed_synchronously) { // Don't recursively call SendMore if this is a sync read. base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&TCPConnectedSocketImpl::SendMore, - weak_ptr_factory_.GetWeakPtr())); + FROM_HERE, base::Bind(&TCPConnectedSocketImpl::SendMore, + weak_ptr_factory_.GetWeakPtr())); } else { SendMore(); } } void TCPConnectedSocketImpl::ShutdownSend() { + send_handle_watcher_.Stop(); pending_send_ = nullptr; send_stream_.reset(); + DeleteIfNeeded(); +} + +void TCPConnectedSocketImpl::ListenForSendPeerClosed() { + send_handle_watcher_.Start( + send_stream_.get(), MOJO_HANDLE_SIGNAL_PEER_CLOSED, + MOJO_DEADLINE_INDEFINITE, + base::Bind(&TCPConnectedSocketImpl::OnSendDataPipeClosed, + weak_ptr_factory_.GetWeakPtr())); +} + +void TCPConnectedSocketImpl::OnSendDataPipeClosed(MojoResult result) { + ShutdownSend(); +} + +void TCPConnectedSocketImpl::DeleteIfNeeded() { + bool has_send = pending_send_ || send_stream_.is_valid(); + bool has_receive = pending_receive_ || receive_stream_.is_valid(); + if (!binding_.is_bound() && !has_send && !has_receive) + delete this; } } // namespace mojo
diff --git a/mojo/services/network/tcp_connected_socket_impl.h b/mojo/services/network/tcp_connected_socket_impl.h index a20f14fb..6e71499 100644 --- a/mojo/services/network/tcp_connected_socket_impl.h +++ b/mojo/services/network/tcp_connected_socket_impl.h
@@ -10,27 +10,33 @@ #include "mojo/common/handle_watcher.h" #include "mojo/services/network/public/interfaces/tcp_connected_socket.mojom.h" #include "net/socket/tcp_socket.h" -#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_impl.h" +#include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h" namespace mojo { class MojoToNetPendingBuffer; class NetToMojoPendingBuffer; -class TCPConnectedSocketImpl : public InterfaceImpl<TCPConnectedSocket> { +class TCPConnectedSocketImpl : public TCPConnectedSocket, public ErrorHandler { public: TCPConnectedSocketImpl(scoped_ptr<net::TCPSocket> socket, ScopedDataPipeConsumerHandle send_stream, - ScopedDataPipeProducerHandle receive_stream); + ScopedDataPipeProducerHandle receive_stream, + InterfaceRequest<TCPConnectedSocket> request); ~TCPConnectedSocketImpl() override; private: + // ErrorHandler methods: + void OnConnectionError() override; + // "Receiving" in this context means reading from TCPSocket and writing to // the Mojo receive_stream. void ReceiveMore(); void OnReceiveStreamReady(MojoResult result); void DidReceive(bool completed_synchronously, int result); void ShutdownReceive(); + void ListenForReceivePeerClosed(); + void OnReceiveDataPipeClosed(MojoResult result); // "Writing" is reading from the Mojo send_stream and writing to the // TCPSocket. @@ -38,6 +44,10 @@ void OnSendStreamReady(MojoResult result); void DidSend(bool completed_asynchronously, int result); void ShutdownSend(); + void ListenForSendPeerClosed(); + void OnSendDataPipeClosed(MojoResult result); + + void DeleteIfNeeded(); scoped_ptr<net::TCPSocket> socket_; @@ -47,13 +57,16 @@ // For reading from the network and writing to Mojo pipe. ScopedDataPipeConsumerHandle send_stream_; - common::HandleWatcher receive_handle_watcher_; scoped_refptr<NetToMojoPendingBuffer> pending_receive_; + common::HandleWatcher receive_handle_watcher_; // For reading from the Mojo pipe and writing to the network. ScopedDataPipeProducerHandle receive_stream_; - common::HandleWatcher send_handle_watcher_; scoped_refptr<MojoToNetPendingBuffer> pending_send_; + common::HandleWatcher send_handle_watcher_; + + // To bind to the message pipe. + Binding<TCPConnectedSocket> binding_; base::WeakPtrFactory<TCPConnectedSocketImpl> weak_ptr_factory_; };
diff --git a/mojo/services/network/tcp_server_socket_impl.cc b/mojo/services/network/tcp_server_socket_impl.cc index 3fb88e0..96ec1e3 100644 --- a/mojo/services/network/tcp_server_socket_impl.cc +++ b/mojo/services/network/tcp_server_socket_impl.cc
@@ -55,10 +55,9 @@ pending_receive_stream_.reset(); pending_client_socket_ = InterfaceRequest<TCPConnectedSocket>(); } else { - BindToRequest(new TCPConnectedSocketImpl( - accepted_socket_.Pass(), - pending_send_stream_.Pass(), - pending_receive_stream_.Pass()), &pending_client_socket_); + new TCPConnectedSocketImpl( + accepted_socket_.Pass(), pending_send_stream_.Pass(), + pending_receive_stream_.Pass(), pending_client_socket_.Pass()); pending_callback_.Run(MakeNetworkError(net::OK), NetAddress::From(accepted_address_)); }
diff --git a/mojo/services/network/udp_socket_apptest.cc b/mojo/services/network/udp_socket_apptest.cc index 9c783f6..d9aa204 100644 --- a/mojo/services/network/udp_socket_apptest.cc +++ b/mojo/services/network/udp_socket_apptest.cc
@@ -5,9 +5,9 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/run_loop.h" +#include "mojo/application/application_test_base_chromium.h" #include "mojo/public/cpp/application/application_connection.h" #include "mojo/public/cpp/application/application_impl.h" -#include "mojo/public/cpp/application/application_test_base.h" #include "mojo/public/cpp/bindings/callback.h" #include "mojo/services/network/public/cpp/udp_socket_wrapper.h" #include "mojo/services/network/public/interfaces/network_service.mojom.h"
diff --git a/mojo/services/network/url_loader_impl_apptest.cc b/mojo/services/network/url_loader_impl_apptest.cc index 4cdbdfb..583fd3d5a 100644 --- a/mojo/services/network/url_loader_impl_apptest.cc +++ b/mojo/services/network/url_loader_impl_apptest.cc
@@ -7,8 +7,8 @@ #include "base/memory/weak_ptr.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" +#include "mojo/application/application_test_base_chromium.h" #include "mojo/common/message_pump_mojo.h" -#include "mojo/public/cpp/application/application_test_base.h" #include "mojo/services/network/network_context.h" #include "mojo/services/network/url_loader_impl.h" #include "net/url_request/url_request_job.h"
diff --git a/mojo/services/view_manager/view_manager_client_apptest.cc b/mojo/services/view_manager/view_manager_client_apptest.cc index 9d441d7..e197c9f 100644 --- a/mojo/services/view_manager/view_manager_client_apptest.cc +++ b/mojo/services/view_manager/view_manager_client_apptest.cc
@@ -11,10 +11,10 @@ #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/test/test_timeouts.h" +#include "mojo/application/application_test_base_chromium.h" #include "mojo/public/cpp/application/application_connection.h" #include "mojo/public/cpp/application/application_delegate.h" #include "mojo/public/cpp/application/application_impl.h" -#include "mojo/public/cpp/application/application_test_base.h" #include "mojo/public/cpp/application/service_provider_impl.h" #include "third_party/mojo_services/src/geometry/public/cpp/geometry_util.h" #include "third_party/mojo_services/src/view_manager/public/cpp/lib/view_manager_client_impl.h"
diff --git a/mojo/services/view_manager/view_manager_service_apptest.cc b/mojo/services/view_manager/view_manager_service_apptest.cc index 1237cc8..67ac384 100644 --- a/mojo/services/view_manager/view_manager_service_apptest.cc +++ b/mojo/services/view_manager/view_manager_service_apptest.cc
@@ -5,9 +5,9 @@ #include "base/bind.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" +#include "mojo/application/application_test_base_chromium.h" #include "mojo/public/cpp/application/application_delegate.h" #include "mojo/public/cpp/application/application_impl.h" -#include "mojo/public/cpp/application/application_test_base.h" #include "mojo/services/view_manager/ids.h" #include "mojo/services/view_manager/test_change_tracker.h" #include "third_party/mojo_services/src/view_manager/public/interfaces/view_manager.mojom.h"
diff --git a/mojo/services/window_manager/BUILD.gn b/mojo/services/window_manager/BUILD.gn index c34ebe1..bb6df15 100644 --- a/mojo/services/window_manager/BUILD.gn +++ b/mojo/services/window_manager/BUILD.gn
@@ -6,23 +6,6 @@ import("//third_party/mojo/src/mojo/public/mojo_application.gni") import("//testing/test.gni") -mojo_native_application("window_manager") { - sources = [ - "main.cc", - ] - - public_deps = [ - ":lib", - ] - - deps = [ - "//base", - "//mojo/application", - "//mojo/common:tracing_impl", - "//third_party/mojo_services/src/view_manager/public/cpp", - ] -} - source_set("lib") { sources = [ "basic_focus_rules.cc", @@ -108,6 +91,24 @@ } } +# A basic window manager with a default delegate used for testing. +mojo_native_application("test_window_manager") { + sources = [ + "main.cc", + ] + + public_deps = [ + ":lib", + ] + + deps = [ + "//base", + "//mojo/application", + "//mojo/common:tracing_impl", + "//third_party/mojo_services/src/view_manager/public/cpp", + ] +} + mojo_native_application("window_manager_apptests") { testonly = true @@ -125,5 +126,5 @@ "//third_party/mojo_services/src/window_manager/public/interfaces", ] - data_deps = [ ":window_manager($default_toolchain)" ] + data_deps = [ ":test_window_manager($default_toolchain)" ] }
diff --git a/mojo/services/window_manager/window_manager_apptest.cc b/mojo/services/window_manager/window_manager_apptest.cc index 7f82211..390c037 100644 --- a/mojo/services/window_manager/window_manager_apptest.cc +++ b/mojo/services/window_manager/window_manager_apptest.cc
@@ -4,9 +4,9 @@ #include "base/bind.h" #include "base/run_loop.h" +#include "mojo/application/application_test_base_chromium.h" #include "mojo/public/cpp/application/application_delegate.h" #include "mojo/public/cpp/application/application_impl.h" -#include "mojo/public/cpp/application/application_test_base.h" #include "mojo/public/cpp/application/service_provider_impl.h" #include "mojo/public/cpp/system/macros.h" #include "third_party/mojo_services/src/view_manager/public/cpp/view.h" @@ -84,7 +84,7 @@ // ApplicationTestBase: void SetUp() override { ApplicationTestBase::SetUp(); - application_impl()->ConnectToService("mojo:window_manager", + application_impl()->ConnectToService("mojo:test_window_manager", &window_manager_); } ApplicationDelegate* GetApplicationDelegate() override {
diff --git a/mojo/shell/BUILD.gn b/mojo/shell/BUILD.gn index 4643e6b..10c5b2c0e 100644 --- a/mojo/shell/BUILD.gn +++ b/mojo/shell/BUILD.gn
@@ -112,8 +112,6 @@ "child_process.h", "child_process_host.cc", "child_process_host.h", - "command_line_util.cc", - "command_line_util.h", "context.cc", "context.h", "filename_util.cc", @@ -361,7 +359,6 @@ test("mojo_shell_tests") { sources = [ "child_process_host_unittest.cc", - "command_line_util_unittest.cc", "data_pipe_peek_unittest.cc", "in_process_native_runner_unittest.cc", "native_runner_unittest.cc",
diff --git a/mojo/shell/android/main.cc b/mojo/shell/android/main.cc index 41c507aa..9caf840 100644 --- a/mojo/shell/android/main.cc +++ b/mojo/shell/android/main.cc
@@ -26,7 +26,6 @@ #include "mojo/shell/android/native_viewport_application_loader.h" #include "mojo/shell/android/ui_application_loader_android.h" #include "mojo/shell/application_manager/application_loader.h" -#include "mojo/shell/command_line_util.h" #include "mojo/shell/context.h" #include "mojo/shell/init.h" #include "ui/gl/gl_surface_egl.h" @@ -46,15 +45,12 @@ class MojoShellRunner : public base::DelegateSimpleThread::Delegate { public: - MojoShellRunner(const std::vector<std::string>& parameters) - : parameters_(parameters) {} + MojoShellRunner(const std::vector<std::string>& parameters) {} ~MojoShellRunner() override {} private: void Run() override; - std::vector<std::string> parameters_; - DISALLOW_COPY_AND_ASSIGN(MojoShellRunner); }; @@ -107,10 +103,7 @@ ConfigureAndroidServices(context); context->Init(); - for (auto& args : parameters_) - ApplyApplicationArgs(context, args); - - RunCommandLineApps(context); + context->Run(GURL("mojo:window_manager")); loop.Run(); g_java_message_loop.Pointer()->get()->PostTask(FROM_HERE,
diff --git a/mojo/shell/application_manager/application_manager.cc b/mojo/shell/application_manager/application_manager.cc index d137fb8..8c908a7 100644 --- a/mojo/shell/application_manager/application_manager.cc +++ b/mojo/shell/application_manager/application_manager.cc
@@ -29,17 +29,6 @@ // Used by TestAPI. bool has_created_instance = false; -std::vector<std::string> Concatenate(const std::vector<std::string>& v1, - const std::vector<std::string>& v2) { - if (!v1.size()) - return v2; - if (!v2.size()) - return v1; - std::vector<std::string> result(v1); - result.insert(result.end(), v1.begin(), v1.end()); - return result; -} - } // namespace ApplicationManager::Delegate::~Delegate() { @@ -154,32 +143,31 @@ } // The application is not running, let's compute the parameters. - std::vector<std::string> parameters = - Concatenate(pre_redirect_parameters, GetArgsForURL(resolved_url)); - if (ConnectToApplicationWithLoader(mapped_url, requestor_url, &services, &exposed_services, on_application_end, - parameters, GetLoaderForURL(mapped_url))) { - return; - } - - if (ConnectToApplicationWithLoader( - resolved_url, requestor_url, &services, &exposed_services, - on_application_end, parameters, GetLoaderForURL(resolved_url))) { + pre_redirect_parameters, + GetLoaderForURL(mapped_url))) { return; } if (ConnectToApplicationWithLoader(resolved_url, requestor_url, &services, &exposed_services, on_application_end, - parameters, default_loader_.get())) { + pre_redirect_parameters, + GetLoaderForURL(resolved_url))) { return; } - auto callback = base::Bind( - &ApplicationManager::HandleFetchCallback, weak_ptr_factory_.GetWeakPtr(), - requestor_url, base::Passed(services.Pass()), - base::Passed(exposed_services.Pass()), on_application_end, - parameters); + if (ConnectToApplicationWithLoader( + resolved_url, requestor_url, &services, &exposed_services, + on_application_end, pre_redirect_parameters, default_loader_.get())) { + return; + } + + auto callback = base::Bind(&ApplicationManager::HandleFetchCallback, + weak_ptr_factory_.GetWeakPtr(), requestor_url, + base::Passed(services.Pass()), + base::Passed(exposed_services.Pass()), + on_application_end, pre_redirect_parameters); if (resolved_url.SchemeIsFile()) { new LocalFetcher( @@ -375,22 +363,6 @@ weak_ptr_factory_.GetWeakPtr(), runner)); } -void ApplicationManager::RegisterExternalApplication( - const GURL& url, - const std::vector<std::string>& args, - ApplicationPtr application) { - const auto& args_it = url_to_args_.find(url); - if (args_it != url_to_args_.end()) { - LOG(WARNING) << "--args-for provided for external application " << url - << " <ignored>"; - } - Identity identity(url); - ShellImpl* shell_impl = - new ShellImpl(application.Pass(), this, identity, base::Closure()); - identity_to_shell_impl_[identity] = shell_impl; - shell_impl->InitializeApplication(Array<String>::From(args)); -} - void ApplicationManager::RegisterContentHandler( const std::string& mime_type, const GURL& content_handler_url) { @@ -434,21 +406,6 @@ scheme_to_loader_[scheme] = loader.release(); } -void ApplicationManager::SetArgsForURL(const std::vector<std::string>& args, - const GURL& url) { - url_to_args_[url].insert(url_to_args_[url].end(), args.begin(), args.end()); - GURL mapped_url = delegate_->ResolveMappings(url); - if (mapped_url != url) { - url_to_args_[mapped_url].insert(url_to_args_[mapped_url].end(), - args.begin(), args.end()); - } - GURL resolved_url = delegate_->ResolveURL(mapped_url); - if (resolved_url != mapped_url) { - url_to_args_[resolved_url].insert(url_to_args_[resolved_url].end(), - args.begin(), args.end()); - } -} - void ApplicationManager::SetNativeOptionsForURL( const NativeRunnerFactory::Options& options, const GURL& url) { @@ -507,13 +464,6 @@ return pipe.handle0.Pass(); } -std::vector<std::string> ApplicationManager::GetArgsForURL(const GURL& url) { - const auto& args_it = url_to_args_.find(url); - if (args_it != url_to_args_.end()) - return args_it->second; - return std::vector<std::string>(); -} - void ApplicationManager::CleanupRunner(NativeRunner* runner) { native_runners_.erase( std::find(native_runners_.begin(), native_runners_.end(), runner));
diff --git a/mojo/shell/application_manager/application_manager.h b/mojo/shell/application_manager/application_manager.h index d0d3a40..44e581d 100644 --- a/mojo/shell/application_manager/application_manager.h +++ b/mojo/shell/application_manager/application_manager.h
@@ -83,10 +83,6 @@ void RegisterContentHandler(const std::string& mime_type, const GURL& content_handler_url); - void RegisterExternalApplication(const GURL& application_url, - const std::vector<std::string>& args, - ApplicationPtr application); - // Sets the default Loader to be used if not overridden by SetLoaderForURL() // or SetLoaderForScheme(). void set_default_loader(scoped_ptr<ApplicationLoader> loader) { @@ -105,11 +101,6 @@ // Sets a Loader to be used for a specific url scheme. void SetLoaderForScheme(scoped_ptr<ApplicationLoader> loader, const std::string& scheme); - // These strings will be passed to the Initialize() method when an Application - // is instantiated. - // TODO(vtl): Maybe we should store/compare resolved URLs, like - // SetNativeOptionsForURL() below? - void SetArgsForURL(const std::vector<std::string>& args, const GURL& url); // These options will be used in running any native application at |url| // (which shouldn't contain a query string). (|url| will be mapped and // resolved, and any application whose base resolved URL matches it will have @@ -135,7 +126,6 @@ typedef std::map<GURL, ApplicationLoader*> URLToLoaderMap; typedef std::map<Identity, ShellImpl*> IdentityToShellImplMap; typedef std::map<GURL, ContentHandlerConnection*> URLToContentHandlerMap; - typedef std::map<GURL, std::vector<std::string>> URLToArgsMap; typedef std::map<std::string, GURL> MimeTypeToURLMap; typedef std::map<GURL, NativeRunnerFactory::Options> URLToNativeOptionsMap; @@ -204,9 +194,6 @@ // Removes a ContentHandler when it encounters an error. void OnContentHandlerError(ContentHandlerConnection* content_handler); - // Returns the arguments for the given url. - std::vector<std::string> GetArgsForURL(const GURL& url); - void CleanupRunner(NativeRunner* runner); Delegate* const delegate_; @@ -219,7 +206,6 @@ IdentityToShellImplMap identity_to_shell_impl_; URLToContentHandlerMap url_to_content_handler_; - URLToArgsMap url_to_args_; // Note: The keys are URLs after mapping and resolving. URLToNativeOptionsMap url_to_native_options_;
diff --git a/mojo/shell/application_manager/application_manager_unittest.cc b/mojo/shell/application_manager/application_manager_unittest.cc index ed16d15..cc420a7 100644 --- a/mojo/shell/application_manager/application_manager_unittest.cc +++ b/mojo/shell/application_manager/application_manager_unittest.cc
@@ -419,34 +419,6 @@ std::map<GURL, GURL> mappings_; }; -class TestExternal : public ApplicationDelegate { - public: - TestExternal() : configure_incoming_connection_called_(false) {} - - void Initialize(ApplicationImpl* app) override { - initialize_args_ = app->args(); - base::MessageLoop::current()->Quit(); - } - - bool ConfigureIncomingConnection(ApplicationConnection* connection) override { - configure_incoming_connection_called_ = true; - base::MessageLoop::current()->Quit(); - return true; - } - - const std::vector<std::string>& initialize_args() const { - return initialize_args_; - } - - bool configure_incoming_connection_called() const { - return configure_incoming_connection_called_; - } - - private: - std::vector<std::string> initialize_args_; - bool configure_incoming_connection_called_; -}; - class ApplicationManagerTest : public testing::Test { public: ApplicationManagerTest() : tester_context_(&loop_) {} @@ -515,75 +487,6 @@ EXPECT_EQ(0U, app_args.size()); } -// Confirm that arguments are sent to an application. -TEST_F(ApplicationManagerTest, Args) { - ApplicationManager am(&test_delegate_); - GURL test_url("test:test"); - std::vector<std::string> args; - args.push_back("test_arg1"); - args.push_back("test_arg2"); - am.SetArgsForURL(args, test_url); - TestApplicationLoader* loader = new TestApplicationLoader; - loader->set_context(&context_); - am.SetLoaderForURL(scoped_ptr<ApplicationLoader>(loader), test_url); - TestServicePtr test_service; - am.ConnectToService(test_url, &test_service); - TestClient test_client(test_service.Pass()); - test_client.Test("test"); - loop_.Run(); - std::vector<std::string> app_args = loader->GetArgs(); - ASSERT_EQ(args.size(), app_args.size()); - EXPECT_EQ(args[0], app_args[0]); - EXPECT_EQ(args[1], app_args[1]); -} - -// Confirm that arguments are aggregated through mappings. -TEST_F(ApplicationManagerTest, ArgsAndMapping) { - ApplicationManager am(&test_delegate_); - GURL test_url("test:test"); - GURL test_url2("test:test2"); - test_delegate_.AddMapping(test_url, test_url2); - std::vector<std::string> args; - args.push_back("test_arg1"); - args.push_back("test_arg2"); - am.SetArgsForURL(args, test_url); - std::vector<std::string> args2; - args2.push_back("test_arg3"); - args2.push_back("test_arg4"); - am.SetArgsForURL(args2, test_url2); - TestApplicationLoader* loader = new TestApplicationLoader; - loader->set_context(&context_); - am.SetLoaderForURL(scoped_ptr<ApplicationLoader>(loader), test_url2); - { - // Connext to the mapped url - TestServicePtr test_service; - am.ConnectToService(test_url, &test_service); - TestClient test_client(test_service.Pass()); - test_client.Test("test"); - loop_.Run(); - std::vector<std::string> app_args = loader->GetArgs(); - ASSERT_EQ(args.size() + args2.size(), app_args.size()); - EXPECT_EQ(args[0], app_args[0]); - EXPECT_EQ(args[1], app_args[1]); - EXPECT_EQ(args2[0], app_args[2]); - EXPECT_EQ(args2[1], app_args[3]); - } - { - // Connext to the target url - TestServicePtr test_service; - am.ConnectToService(test_url2, &test_service); - TestClient test_client(test_service.Pass()); - test_client.Test("test"); - loop_.Run(); - std::vector<std::string> app_args = loader->GetArgs(); - ASSERT_EQ(args.size() + args2.size(), app_args.size()); - EXPECT_EQ(args[0], app_args[0]); - EXPECT_EQ(args[1], app_args[1]); - EXPECT_EQ(args2[0], app_args[2]); - EXPECT_EQ(args2[1], app_args[3]); - } -} - TEST_F(ApplicationManagerTest, ClientError) { test_client_->Test("test"); EXPECT_TRUE(HasFactoryForTestURL()); @@ -773,22 +676,6 @@ custom_loader->set_context(nullptr); } -TEST_F(ApplicationManagerTest, ExternalApp) { - ApplicationPtr application; - TestExternal external; - std::vector<std::string> args; - args.push_back("test"); - ApplicationImpl app(&external, GetProxy(&application)); - application_manager_->RegisterExternalApplication(GURL("mojo:test"), args, - application.Pass()); - loop_.Run(); - EXPECT_EQ(args, external.initialize_args()); - application_manager_->ConnectToServiceByName(GURL("mojo:test"), - std::string()); - loop_.Run(); - EXPECT_TRUE(external.configure_incoming_connection_called()); -}; - TEST_F(ApplicationManagerTest, TestQueryWithLoaders) { TestApplicationLoader* url_loader = new TestApplicationLoader; TestApplicationLoader* scheme_loader = new TestApplicationLoader;
diff --git a/mojo/shell/command_line_util.cc b/mojo/shell/command_line_util.cc deleted file mode 100644 index 68bdfa4d..0000000 --- a/mojo/shell/command_line_util.cc +++ /dev/null
@@ -1,90 +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 "mojo/shell/command_line_util.h" - -#include <functional> - -#include "base/command_line.h" -#include "base/logging.h" -#include "base/strings/string_split.h" -#include "base/strings/utf_string_conversions.h" -#include "mojo/shell/context.h" -#include "mojo/shell/switches.h" - -namespace mojo { -namespace shell { - -namespace { -GURL GetAppURLAndSetArgs(const std::string& app_url_and_args, - Context* context) { - std::vector<std::string> args; - GURL app_url = GetAppURLAndArgs(context, app_url_and_args, &args); - - if (args.size() > 1) - context->application_manager()->SetArgsForURL(args, app_url); - return app_url; -} -} // namespace - -bool ParseArgsFor(const std::string& arg, std::string* value) { - const std::string kArgsForSwitches[] = { - "-" + std::string(switches::kArgsFor) + "=", - "--" + std::string(switches::kArgsFor) + "=", - }; - for (size_t i = 0; i < arraysize(kArgsForSwitches); i++) { - const std::string& argsfor_switch = kArgsForSwitches[i]; - if (arg.compare(0, argsfor_switch.size(), argsfor_switch) == 0) { - *value = arg.substr(argsfor_switch.size(), std::string::npos); - return true; - } - } - return false; -} - -GURL GetAppURLAndArgs(Context* context, - const std::string& app_url_and_args, - std::vector<std::string>* args) { - // SplitString() returns empty strings for extra delimeter characters (' '). - base::SplitString(app_url_and_args, ' ', args); - args->erase(std::remove_if(args->begin(), args->end(), - std::mem_fun_ref(&std::string::empty)), - args->end()); - - if (args->empty()) - return GURL(); - GURL app_url = context->ResolveCommandLineURL((*args)[0]); - if (!app_url.is_valid()) { - LOG(ERROR) << "Error: invalid URL: " << (*args)[0]; - return app_url; - } - if (args->size() == 1) - args->clear(); - return app_url; -} - -void ApplyApplicationArgs(Context* context, const std::string& args) { - std::string args_for_value; - if (ParseArgsFor(args, &args_for_value)) - GetAppURLAndSetArgs(args_for_value, context); -} - -void RunCommandLineApps(Context* context) { - const auto& command_line = *base::CommandLine::ForCurrentProcess(); - for (const auto& arg : command_line.GetArgs()) { - std::string arg2; -#if defined(OS_WIN) - arg2 = base::UTF16ToUTF8(arg); -#else - arg2 = arg; -#endif - GURL url = GetAppURLAndSetArgs(arg2, context); - if (!url.is_valid()) - return; - context->Run(url); - } -} - -} // namespace shell -} // namespace mojo
diff --git a/mojo/shell/command_line_util.h b/mojo/shell/command_line_util.h deleted file mode 100644 index aa80002..0000000 --- a/mojo/shell/command_line_util.h +++ /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. - -#ifndef SHELL_COMMAND_LINE_UTIL_H_ -#define SHELL_COMMAND_LINE_UTIL_H_ - -#include "mojo/shell/context.h" - -namespace mojo { -namespace shell { - -// Parse the given arg, looking for an --args-for switch. If this is not the -// case, returns |false|. Otherwise, returns |true| and set |*value| to the -// value of the switch. -bool ParseArgsFor(const std::string& arg, std::string* value); - -// The value of app_url_and_args is "<mojo_app_url> [<args>...]", where args -// is a list of "configuration" arguments separated by spaces. If one or more -// arguments are specified they will be available when the Mojo application -// is initialized. This returns the mojo_app_url, and set args to the list of -// arguments. -GURL GetAppURLAndArgs(Context* context, - const std::string& app_url_and_args, - std::vector<std::string>* args); - -// Apply arguments for an application from a line with the following format: -// '--args-for=application_url arg1 arg2 arg3' -// This does nothing if the line has not the right format. -void ApplyApplicationArgs(Context* context, const std::string& args); - -// Run all application defined on the command line, using the given context. -void RunCommandLineApps(Context* context); - -} // namespace shell -} // namespace mojo - -#endif // SHELL_COMMAND_LINE_UTIL_H_
diff --git a/mojo/shell/command_line_util_unittest.cc b/mojo/shell/command_line_util_unittest.cc deleted file mode 100644 index 547aa86..0000000 --- a/mojo/shell/command_line_util_unittest.cc +++ /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. - -#include "mojo/shell/command_line_util.h" - -#include "base/logging.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace mojo { -namespace shell { -namespace { - -TEST(CommandLineUtil, ParseArgsFor) { - static const struct Expectation { - const char* args; - const char* value; - } EXPECTATIONS[] = { - {"", nullptr}, - {"hello", nullptr}, - {"args-for=mojo:app1", nullptr}, - {"--args-for", nullptr}, - {"--args-for=", ""}, - {"--args-for=mojo:app1", "mojo:app1"}, - {"--args-for=mojo:app1 hello world", "mojo:app1 hello world"}, - {"-args-for", nullptr}, - {"-args-for=", ""}, - {"-args-for=mojo:app1", "mojo:app1"}, - {"-args-for=mojo:app1 hello world", "mojo:app1 hello world"}}; - for (auto& expectation : EXPECTATIONS) { - std::string value; - bool result = ParseArgsFor(expectation.args, &value); - EXPECT_EQ(bool(expectation.value), result); - if (expectation.value && result) - EXPECT_EQ(value, expectation.value); - } -} - -TEST(CommandLineUtil, GetAppURLAndArgs) { - const char* NO_ARGUMENTS[] = {nullptr}; - const char* ONE_ARGUMENTS[] = {"1", nullptr}; - const char* TWO_ARGUMENTS[] = {"1", "two", nullptr}; - static const struct Expectation { - const char* args; - const char* url; - const char** values; - } EXPECTATIONS[] = { - {"", nullptr, nullptr}, - {"foo", "file:///root/foo", NO_ARGUMENTS}, - {"/foo", "file:///foo", NO_ARGUMENTS}, - {"file:foo", "file:///root/foo", NO_ARGUMENTS}, - {"file:///foo", "file:///foo", NO_ARGUMENTS}, - {"http://example.com", "http://example.com", NO_ARGUMENTS}, - {"http://example.com 1", "http://example.com", ONE_ARGUMENTS}, - {"http://example.com 1 ", "http://example.com", ONE_ARGUMENTS}, - {"http://example.com 1 ", "http://example.com", ONE_ARGUMENTS}, - {"http://example.com 1 two", "http://example.com", TWO_ARGUMENTS}, - {" http://example.com 1 two ", - "http://example.com", - TWO_ARGUMENTS}}; - Context context; - context.SetCommandLineCWD(base::FilePath(FILE_PATH_LITERAL("/root"))); - for (auto& expectation : EXPECTATIONS) { - std::vector<std::string> args; - GURL result(GetAppURLAndArgs(&context, expectation.args, &args)); - EXPECT_EQ(bool(expectation.url), result.is_valid()); - if (expectation.url && result.is_valid()) { - EXPECT_EQ(GURL(expectation.url), result); - std::vector<std::string> expected_args; - if (expectation.values) { - if (*expectation.values) - expected_args.push_back(expectation.url); - for (const char** value = expectation.values; *value; ++value) - expected_args.push_back(*value); - } - EXPECT_EQ(expected_args, args); - } - } -} - -} // namespace -} // namespace shell -} // namespace mojo
diff --git a/mojo/shell/context.cc b/mojo/shell/context.cc index fbde07d..fc56476f 100644 --- a/mojo/shell/context.cc +++ b/mojo/shell/context.cc
@@ -30,7 +30,6 @@ #include "mojo/services/tracing/tracing.mojom.h" #include "mojo/shell/application_manager/application_loader.h" #include "mojo/shell/application_manager/application_manager.h" -#include "mojo/shell/command_line_util.h" #include "mojo/shell/filename_util.h" #include "mojo/shell/in_process_native_runner.h" #include "mojo/shell/out_of_process_native_runner.h" @@ -85,22 +84,6 @@ resolver->AddOriginMapping(GURL(origin_mapping.origin), GURL(origin_mapping.base_url)); - if (command_line.HasSwitch(switches::kURLMappings)) { - const std::string mappings = - command_line.GetSwitchValueASCII(switches::kURLMappings); - - base::StringPairs pairs; - if (!base::SplitStringIntoKeyValuePairs(mappings, '=', ',', &pairs)) - return false; - using StringPair = std::pair<std::string, std::string>; - for (const StringPair& pair : pairs) { - const GURL from(pair.first); - const GURL to = context->ResolveCommandLineURL(pair.second); - if (!from.is_valid() || !to.is_valid()) - return false; - resolver->AddURLMapping(from, to); - } - } return true; }
diff --git a/mojo/shell/desktop/launcher_process.cc b/mojo/shell/desktop/launcher_process.cc index f6bb6ded..1b47cc8 100644 --- a/mojo/shell/desktop/launcher_process.cc +++ b/mojo/shell/desktop/launcher_process.cc
@@ -15,7 +15,6 @@ #include "base/message_loop/message_loop.h" #include "base/synchronization/waitable_event.h" #include "base/trace_event/trace_event.h" -#include "mojo/shell/command_line_util.h" #include "mojo/shell/context.h" #include "mojo/shell/switches.h" @@ -23,29 +22,6 @@ namespace shell { namespace { -void Usage() { - std::cerr << "Launch Mojo applications.\n"; - std::cerr - << "Usage: mojo_shell" - << " [--" << switches::kArgsFor << "=<mojo-app>]" - << " [--" << switches::kContentHandlers << "=<handlers>]" - << " [--" << switches::kDisableCache << "]" - << " [--" << switches::kEnableMultiprocess << "]" - << " [--" << switches::kOrigin << "=<url-lib-path>]" - << " [--" << switches::kTraceStartup << "]" - << " [--" << switches::kURLMappings << "=from1=to1,from2=to2]" - << " [--" << switches::kPredictableAppFilenames << "]" - << " [--" << switches::kWaitForDebugger << "]" - << " <mojo-app> ...\n\n" - << "A <mojo-app> is a Mojo URL or a Mojo URL and arguments within " - << "quotes.\n" - << "Example: mojo_shell \"mojo:js_standalone test.js\".\n" - << "<url-lib-path> is searched for shared libraries named by mojo URLs.\n" - << "The value of <handlers> is a comma separated list like:\n" - << "text/html,mojo:html_viewer," - << "application/javascript,mojo:js_content_handler\n"; -} - // Whether we're currently tracing. bool g_tracing = false; @@ -99,28 +75,28 @@ flush_complete_event.Wait(); } +void StartApp(mojo::shell::Context* context) { + // If a mojo app isn't specified (i.e. for an apptest), run the mojo shell's + // window manager. + GURL app_url(GURL("mojo:window_manager")); + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + base::CommandLine::StringVector args = command_line->GetArgs(); + for (size_t i = 0; i < args.size(); ++i) { + GURL possible_app(args[i]); + if (possible_app.SchemeIs("mojo")) { + app_url = possible_app; + break; + } + } + + context->Run(app_url); +} + } // namespace int LauncherProcessMain(int argc, char** argv) { const base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess(); - - const std::set<std::string> all_switches = switches::GetAllSwitches(); - const base::CommandLine::SwitchMap switches = command_line.GetSwitches(); - bool found_unknown_switch = false; - for (const auto& s : switches) { - if (all_switches.find(s.first) == all_switches.end()) { - std::cerr << "unknown switch: " << s.first << std::endl; - found_unknown_switch = true; - } - } - - if (found_unknown_switch || command_line.HasSwitch(switches::kHelp) || - command_line.GetArgs().empty()) { - Usage(); - return 0; - } - if (command_line.HasSwitch(switches::kTraceStartup)) { g_tracing = true; base::trace_event::CategoryFilter category_filter( @@ -136,7 +112,6 @@ { base::MessageLoop message_loop; if (!shell_context.Init()) { - Usage(); return 0; } if (g_tracing) { @@ -145,16 +120,7 @@ base::TimeDelta::FromSeconds(5)); } - // The mojo_shell --args-for command-line switch is handled specially - // because it can appear more than once. The base::CommandLine class - // collapses multiple occurrences of the same switch. - for (int i = 1; i < argc; i++) { - ApplyApplicationArgs(&shell_context, argv[i]); - } - - message_loop.PostTask( - FROM_HERE, - base::Bind(&mojo::shell::RunCommandLineApps, &shell_context)); + message_loop.PostTask(FROM_HERE, base::Bind(&StartApp, &shell_context)); message_loop.Run(); // Must be called before |message_loop| is destroyed.
diff --git a/mojo/shell/native_application_support.cc b/mojo/shell/native_application_support.cc index 55ae2cf..9df3ed88 100644 --- a/mojo/shell/native_application_support.cc +++ b/mojo/shell/native_application_support.cc
@@ -4,6 +4,7 @@ #include "mojo/shell/native_application_support.h" +#include "base/command_line.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/logging.h" @@ -104,6 +105,26 @@ init_go_runtime(); } +#if !defined(OS_WIN) + // On Windows, initializing base::CommandLine with null parameters gets the + // process's command line from the OS. Other platforms need it to be passed + // in. This needs to be passed in before the app initializes the command line, + // which is done as soon as it loads. + typedef void (*InitCommandLineArgs)(int, const char* const*); + InitCommandLineArgs init_command_line_args = + reinterpret_cast<InitCommandLineArgs>( + base::GetFunctionPointerFromNativeLibrary(app_library, + "InitCommandLineArgs")); + if (init_command_line_args) { + int argc = 0; + base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); + const char** argv = new const char* [cmd_line->argv().size()]; + for (auto& arg : cmd_line->argv()) + argv[argc++] = arg.c_str(); + init_command_line_args(argc, argv); + } +#endif + typedef MojoResult (*MojoMainFunction)(MojoHandle); MojoMainFunction main_function = reinterpret_cast<MojoMainFunction>( base::GetFunctionPointerFromNativeLibrary(app_library, "MojoMain"));
diff --git a/mojo/shell/shell_apptest.cc b/mojo/shell/shell_apptest.cc index 1acdf7d..66b6889 100644 --- a/mojo/shell/shell_apptest.cc +++ b/mojo/shell/shell_apptest.cc
@@ -10,9 +10,9 @@ #include "base/run_loop.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" +#include "mojo/application/application_test_base_chromium.h" #include "mojo/common/data_pipe_utils.h" #include "mojo/public/cpp/application/application_impl.h" -#include "mojo/public/cpp/application/application_test_base.h" #include "mojo/public/cpp/system/macros.h" #include "mojo/services/http_server/public/cpp/http_server_util.h" #include "mojo/services/http_server/public/interfaces/http_server.mojom.h"
diff --git a/mojo/shell/switches.cc b/mojo/shell/switches.cc index 2150b19..28e7d058 100644 --- a/mojo/shell/switches.cc +++ b/mojo/shell/switches.cc
@@ -8,18 +8,6 @@ namespace switches { -namespace { -// This controls logging verbosity. It's not strictly a switch for mojo_shell, -// and isn't included in the public switches, but is included here so that it -// doesn't trigger an error at startup. -const char kV[] = "v"; - -} // namespace - -// Specify configuration arguments for a Mojo application URL. For example: -// --args-for='mojo:wget http://www.google.com' -const char kArgsFor[] = "args-for"; - // Used internally by the main process to indicate that a new process should be // a child process. Not for user use. const char kChildProcess[] = "child-process"; @@ -67,34 +55,4 @@ // seconds or when the shell exits. const char kTraceStartup[] = "trace-startup"; -// Specifies a set of mappings to apply when resolving urls. The value is a set -// of ',' separated mappings, where each mapping consists of a pair of urls -// giving the to/from url to map. For example, 'a=b,c=d' contains two mappings, -// the first maps 'a' to 'b' and the second 'c' to 'd'. -const char kURLMappings[] = "url-mappings"; - -// Switches valid for the main process (i.e., that the user may pass in). -const char* kSwitchArray[] = {kV, - kArgsFor, - // |kChildProcess| not for user use. - kContentHandlers, - kDisableCache, - kDontDeleteOnDownload, - kEnableMultiprocess, - kForceInProcess, - kHelp, - kMapOrigin, - kOrigin, - kPredictableAppFilenames, - kTraceStartup, - kURLMappings}; - -const std::set<std::string> GetAllSwitches() { - std::set<std::string> switch_set; - - for (size_t i = 0; i < arraysize(kSwitchArray); ++i) - switch_set.insert(kSwitchArray[i]); - return switch_set; -} - } // namespace switches
diff --git a/mojo/shell/switches.h b/mojo/shell/switches.h index 52267fec..ff2eb6c 100644 --- a/mojo/shell/switches.h +++ b/mojo/shell/switches.h
@@ -11,9 +11,7 @@ namespace switches { // All switches in alphabetical order. The switches should be documented -// alongside the definition of their values in the .cc file and, as needed, -// in mojo_main's Usage() function. -extern const char kArgsFor[]; +// alongside the definition of their values in the .cc file. extern const char kChildProcess[]; extern const char kContentHandlers[]; extern const char kDisableCache[]; @@ -25,9 +23,6 @@ extern const char kOrigin[]; extern const char kPredictableAppFilenames[]; extern const char kTraceStartup[]; -extern const char kURLMappings[]; - -extern const std::set<std::string> GetAllSwitches(); } // namespace switches
diff --git a/mojo/shell/url_resolver_unittest.cc b/mojo/shell/url_resolver_unittest.cc index f9593216..dd8da75 100644 --- a/mojo/shell/url_resolver_unittest.cc +++ b/mojo/shell/url_resolver_unittest.cc
@@ -115,7 +115,6 @@ args.clear(); args.push_back(ARG_LITERAL("mojo_shell")); - args.push_back(ARG_LITERAL("--args-for=https://a.org/foo --test")); args.push_back(ARG_LITERAL("--map-origin=https://a.org=https://b.org/a")); args.push_back(ARG_LITERAL("--map-origin=https://b.org=https://c.org/b")); args.push_back(ARG_LITERAL("https://a.org/foo"));
diff --git a/mojo/tools/android_mojo_shell.py b/mojo/tools/android_mojo_shell.py index d731afe9..e269228 100755 --- a/mojo/tools/android_mojo_shell.py +++ b/mojo/tools/android_mojo_shell.py
@@ -10,28 +10,10 @@ from mopy.config import Config from mopy import android -USAGE = ("android_mojo_shell.py " - "[--args-for=<mojo-app>] " - "[--content-handlers=<handlers>] " - "[--enable-external-applications] " - "[--disable-cache] " - "[--enable-multiprocess] " - "[--url-mappings=from1=to1,from2=to2] " - "[<mojo-app>] " - """ - -A <mojo-app> is a Mojo URL or a Mojo URL and arguments within quotes. -Example: mojo_shell "mojo:js_standalone test.js". -<url-lib-path> is searched for shared libraries named by mojo URLs. -The value of <handlers> is a comma separated list like: -text/html,mojo:html_viewer,application/javascript,mojo:js_content_handler -""") - - def main(): logging.basicConfig() - parser = argparse.ArgumentParser(usage=USAGE) + parser = argparse.ArgumentParser("Helper for running mojo_shell") debug_group = parser.add_mutually_exclusive_group() debug_group.add_argument('--debug', help='Debug build (default)',
diff --git a/mojo/tools/apptest_runner.py b/mojo/tools/apptest_runner.py index 901babfa..9ef7b7aa 100755 --- a/mojo/tools/apptest_runner.py +++ b/mojo/tools/apptest_runner.py
@@ -59,8 +59,7 @@ apptest_result = "Succeeded" for fixture in fixtures: - args_for_apptest = " ".join(["--args-for=" + apptest, - "--gtest_filter=" + fixture] + apptest_args) + args_for_apptest = " ".join(["--gtest_filter=" + fixture] + apptest_args) success = RunApptestInShell(mojo_shell_path, apptest, shell_args + [args_for_apptest])
diff --git a/mojo/tools/gtest.py b/mojo/tools/gtest.py index c03b62f4..d84c8e5e 100644 --- a/mojo/tools/gtest.py +++ b/mojo/tools/gtest.py
@@ -70,9 +70,7 @@ [TestSuite.TestFixture, ... ] An empty list is returned on failure, with errors logged. """ - command = [mojo_shell, - "--args-for={0} --gtest_list_tests".format(apptest), - apptest] + command = [mojo_shell, "--gtest_list_tests", apptest] try: list_output = subprocess.check_output(command, stderr=subprocess.STDOUT) _logging.debug("Tests listed:\n%s" % list_output)
diff --git a/native_client_sdk/src/build_tools/build_sdk.py b/native_client_sdk/src/build_tools/build_sdk.py index f424d3d9..fc7fc3e3 100755 --- a/native_client_sdk/src/build_tools/build_sdk.py +++ b/native_client_sdk/src/build_tools/build_sdk.py
@@ -828,14 +828,21 @@ return bundle +def Archive(filename, from_directory, step_link=True): + if buildbot_common.IsSDKBuilder(): + bucket_path = 'nativeclient-mirror/nacl/nacl_sdk/' + else: + bucket_path = 'nativeclient-mirror/nacl/nacl_sdk_test/' + bucket_path += build_version.ChromeVersion() + buildbot_common.Archive(filename, bucket_path, from_directory, step_link) + + def BuildStepArchiveBundle(name, pepper_ver, chrome_revision, nacl_revision, tarfile): buildbot_common.BuildStep('Archive %s' % name) - bucket_path = 'nativeclient-mirror/nacl/nacl_sdk/%s' % ( - build_version.ChromeVersion(),) tarname = os.path.basename(tarfile) tarfile_dir = os.path.dirname(tarfile) - buildbot_common.Archive(tarname, bucket_path, tarfile_dir) + Archive(tarname, tarfile_dir) # generate "manifest snippet" for this archive. archive_url = GSTORE + 'nacl_sdk/%s/%s' % ( @@ -847,24 +854,37 @@ with open(manifest_snippet_file, 'wb') as manifest_snippet_stream: manifest_snippet_stream.write(bundle.GetDataAsString()) - buildbot_common.Archive(tarname + '.json', bucket_path, OUT_DIR, - step_link=False) + Archive(tarname + '.json', OUT_DIR, step_link=False) + + +def BuildStepBuildPNaClComponent(version, revision): + # Sadly revision can go backwords for a given version since when a version + # is built from master, revision will be a huge number (in the hundreds of + # thousands. Once the branch happens the revision will reset to zero. + # TODO(sbc): figure out how to compensate for this in some way such that + # revisions always go forward for a given version. + buildbot_common.BuildStep('PNaCl Component') + if len(revision) > 4: + rev_minor = revision[-4:] + rev_major = revision[:-4] + version = "0.%s.%s.%s" % (version, rev_major, rev_minor) + else: + version = "0.%s.0.%s" % (version, revision) + buildbot_common.Run(['./make_pnacl_component.sh', version], cwd=SCRIPT_DIR) + + +def BuildStepArchivePNaClComponent(): + buildbot_common.BuildStep('Archive PNaCl Component') + Archive('pnacl_multicrx.zip', OUT_DIR) def BuildStepArchiveSDKTools(): - # Only push up sdk_tools.tgz and nacl_sdk.zip on the linux buildbot. - builder_name = os.getenv('BUILDBOT_BUILDERNAME', '') - if builder_name == 'linux-sdk-multi': - buildbot_common.BuildStep('Build SDK Tools') - build_updater.BuildUpdater(OUT_DIR) + buildbot_common.BuildStep('Build SDK Tools') + build_updater.BuildUpdater(OUT_DIR) - buildbot_common.BuildStep('Archive SDK Tools') - bucket_path = 'nativeclient-mirror/nacl/nacl_sdk/%s' % ( - build_version.ChromeVersion(),) - buildbot_common.Archive('sdk_tools.tgz', bucket_path, OUT_DIR, - step_link=False) - buildbot_common.Archive('nacl_sdk.zip', bucket_path, OUT_DIR, - step_link=False) + buildbot_common.BuildStep('Archive SDK Tools') + Archive('sdk_tools.tgz', OUT_DIR, step_link=False) + Archive('nacl_sdk.zip', OUT_DIR, step_link=False) def BuildStepSyncNaClPorts(): @@ -1123,12 +1143,15 @@ if options.tar: BuildStepTarBundle(pepper_ver, tarfile) - if options.build_ports and platform == 'linux': - ports_tarfile = os.path.join(OUT_DIR, 'naclports.tar.bz2') - BuildStepSyncNaClPorts() - BuildStepBuildNaClPorts(pepper_ver, pepperdir) - if options.tar: - BuildStepTarNaClPorts(pepper_ver, ports_tarfile) + if platform == 'linux': + BuildStepBuildPNaClComponent(pepper_ver, chrome_revision) + + if options.build_ports: + ports_tarfile = os.path.join(OUT_DIR, 'naclports.tar.bz2') + BuildStepSyncNaClPorts() + BuildStepBuildNaClPorts(pepper_ver, pepperdir) + if options.tar: + BuildStepTarNaClPorts(pepper_ver, ports_tarfile) if options.build_app_engine and platform == 'linux': BuildStepBuildAppEngine(pepperdir, chrome_revision) @@ -1137,14 +1160,17 @@ qemudir = os.path.join(NACL_DIR, 'toolchain', 'linux_arm-trusted') oshelpers.Copy(['-r', qemudir, pepperdir]) - # Archive on non-trybots. + # Archive the results on Google Cloud Storage. if options.archive: BuildStepArchiveBundle('build', pepper_ver, chrome_revision, nacl_revision, tarfile) - if options.build_ports and platform == 'linux': - BuildStepArchiveBundle('naclports', pepper_ver, chrome_revision, - nacl_revision, ports_tarfile) - BuildStepArchiveSDKTools() + # Only archive sdk_tools/naclport/pnacl_component on linux. + if platform == 'linux': + if options.build_ports: + BuildStepArchiveBundle('naclports', pepper_ver, chrome_revision, + nacl_revision, ports_tarfile) + BuildStepArchiveSDKTools() + BuildStepArchivePNaClComponent() return 0
diff --git a/native_client_sdk/src/build_tools/buildbot_common.py b/native_client_sdk/src/build_tools/buildbot_common.py index 37aace9..58ebc0a 100644 --- a/native_client_sdk/src/build_tools/buildbot_common.py +++ b/native_client_sdk/src/build_tools/buildbot_common.py
@@ -37,15 +37,6 @@ return '-sdk-multi' in bot or '-sdk-bionic-multi' in bot -def IsSDKTrybot(): - """Returns True if this script is running on an SDK trybot. - - False means it is either running on an SDK builder, or a user's machine. - - See IsSDKBuilder above for trybot/buildbot names.""" - return '_nacl_sdk' in os.getenv('BUILDBOT_BUILDERNAME', '') - - def ErrorExit(msg): """Write and error to stderr, then exit with 1 signaling failure.""" sys.stderr.write(str(msg) + '\n')
diff --git a/native_client_sdk/src/build_tools/make_pnacl_component.sh b/native_client_sdk/src/build_tools/make_pnacl_component.sh new file mode 100755 index 0000000..42dc040 --- /dev/null +++ b/native_client_sdk/src/build_tools/make_pnacl_component.sh
@@ -0,0 +1,103 @@ +#!/bin/bash +# 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 script builds out/pnacl_multicrx.zip for upload to the Chrome +# Web Store. It runs gyp + ninja once for each architecture and assembles +# the results along with a manifest file. + +# TODO(sbc): rewrite this in python + +set -o errexit +set -o nounset + +SCRIPT_DIR="$(cd $(dirname $0) && pwd)" +CHROME_SRC=$(dirname $(dirname $(dirname ${SCRIPT_DIR}))) +cd ${CHROME_SRC} + +run_gyp() { + # The original version of the script ran 'gclient runhooks' which run turn + # runs gyp_chromium. However its a lot faster and quieter to just run the + # gyp file containing the target we need. + gyp_dir=ppapi/native_client/src/untrusted/pnacl_support_extension + build/gyp_chromium --depth=. $gyp_dir/pnacl_support_extension.gyp +} + +individual_packages() { + export GYP_GENERATOR_FLAGS="output_dir=out_pnacl" + + # arm + rm -rf out_pnacl/ + GYP_DEFINES="target_arch=arm" run_gyp + ninja -C out_pnacl/Release/ pnacl_support_extension + local target_dir=out/pnacl_arm + mkdir -p ${target_dir} + cp out_pnacl/Release/pnacl/* ${target_dir}/. + + # ia32 + rm -rf out_pnacl/ + GYP_DEFINES="target_arch=ia32" run_gyp + ninja -C out_pnacl/Release/ pnacl_support_extension + target_dir=out/pnacl_x86_32 + mkdir -p ${target_dir} + cp out_pnacl/Release/pnacl/* ${target_dir}/. + + # x64 + rm -rf out_pnacl/ + GYP_DEFINES="target_arch=x64" run_gyp + ninja -C out_pnacl/Release/ pnacl_support_extension + target_dir=out/pnacl_x86_64 + mkdir -p ${target_dir} + cp out_pnacl/Release/pnacl/* ${target_dir}/. +} + +multi_crx() { + local version=$1 + local target_dir=out/pnacl_multicrx + mkdir -p ${target_dir} + cat > ${target_dir}/manifest.json <<EOF +{ + "description": "Portable Native Client Translator Multi-CRX", + "name": "PNaCl Translator Multi-CRX", + "manifest_version": 2, + "minimum_chrome_version": "30.0.0.0", + "version": "${version}", + "platforms": [ + { + "nacl_arch": "x86-32", + "sub_package_path": "_platform_specific/x86_32/" + }, + { + "nacl_arch": "x86-64", + "sub_package_path": "_platform_specific/x86_64/" + }, + { + "nacl_arch": "arm", + "sub_package_path": "_platform_specific/arm/" + } + ] +} +EOF + + for arch in x86_32 x86_64 arm; do + local sub_dir="${target_dir}/_platform_specific/${arch}" + local src_dir="out/pnacl_${arch}" + mkdir -p ${sub_dir} + cp ${src_dir}/pnacl_public_* ${sub_dir}/. + done + (cd ${target_dir} && zip -r ../$(basename ${target_dir}).zip .) + ls -l ${target_dir}.zip + echo "DONE: created ${target_dir}.zip -- upload that!" + echo "You can also delete ${target_dir} later (the pre-zipped contents)." +} + +if [ $# != 1 ]; then + echo "Usage: $0 <rev_number>" + exit 1 +fi + +version="$1" +echo "Buidling pnacl_multicrx.zip version=$version" +individual_packages +multi_crx $version
diff --git a/net/BUILD.gn b/net/BUILD.gn index 05f1106d..9d82fd0 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -863,6 +863,10 @@ "proxy/mojo_proxy_resolver_impl.h", ] + deps = [ + ":net_with_v8", + ] + public_deps = [ ":mojo_type_converters", ":net",
diff --git a/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java b/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java index 32b7192..047a787 100644 --- a/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java +++ b/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java
@@ -12,7 +12,7 @@ import android.util.Log; import org.chromium.base.CalledByNative; -import org.chromium.base.CalledByNativeUnchecked; +import org.chromium.base.annotations.CalledByNativeUnchecked; import java.net.NetworkInterface; import java.net.SocketException;
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc index 1060509..d799758 100644 --- a/net/cookies/cookie_monster.cc +++ b/net/cookies/cookie_monster.cc
@@ -1234,6 +1234,10 @@ } int CookieMonster::DeleteAll(bool sync_to_store) { + // TODO(xiyuan): Remove the log after http://crbug.com/449816. + VLOG(kVlogSetCookies) << "CookieMonster::DeleteAll, sync_to_store=" + << sync_to_store; + base::AutoLock autolock(lock_); int num_deleted = 0; @@ -1252,6 +1256,9 @@ int CookieMonster::DeleteAllCreatedBetween(const Time& delete_begin, const Time& delete_end) { + // TODO(xiyuan): Remove the log after http://crbug.com/449816. + VLOG(kVlogSetCookies) << "CookieMonster::DeleteAllCreatedBetween"; + base::AutoLock autolock(lock_); int num_deleted = 0; @@ -1274,6 +1281,9 @@ int CookieMonster::DeleteAllCreatedBetweenForHost(const Time delete_begin, const Time delete_end, const GURL& url) { + // TODO(xiyuan): Remove the log after http://crbug.com/449816. + VLOG(kVlogSetCookies) << "CookieMonster::DeleteAllCreatedBetweenForHost"; + base::AutoLock autolock(lock_); if (!HasCookieableScheme(url)) @@ -1311,6 +1321,9 @@ } bool CookieMonster::DeleteCanonicalCookie(const CanonicalCookie& cookie) { + // TODO(xiyuan): Remove the log after http://crbug.com/449816. + VLOG(kVlogSetCookies) << "CookieMonster::DeleteCanonicalCookie"; + base::AutoLock autolock(lock_); for (CookieMapItPair its = cookies_.equal_range(GetKey(cookie.Domain())); @@ -1380,6 +1393,9 @@ void CookieMonster::DeleteCookie(const GURL& url, const std::string& cookie_name) { + // TODO(xiyuan): Remove the log after http://crbug.com/449816. + VLOG(kVlogSetCookies) << "CookieMonster::DeleteCookie"; + base::AutoLock autolock(lock_); if (!HasCookieableScheme(url)) @@ -1412,6 +1428,9 @@ } int CookieMonster::DeleteSessionCookies() { + // TODO(xiyuan): Remove the log after http://crbug.com/449816. + VLOG(kVlogSetCookies) << "CookieMonster::DeleteSessionCookies"; + base::AutoLock autolock(lock_); int num_deleted = 0; @@ -1484,9 +1503,15 @@ void CookieMonster::OnLoaded(TimeTicks beginning_time, const std::vector<CanonicalCookie*>& cookies) { + // TODO(pkasting): Remove ScopedTracker below once crbug.com/457528 is fixed. + tracked_objects::ScopedTracker tracking_profile1( + FROM_HERE_WITH_EXPLICIT_FUNCTION("457528 CookieMonster::OnLoaded 1")); StoreLoadedCookies(cookies); histogram_time_blocked_on_load_->AddTime(TimeTicks::Now() - beginning_time); + // TODO(pkasting): Remove ScopedTracker below once crbug.com/457528 is fixed. + tracked_objects::ScopedTracker tracking_profile2( + FROM_HERE_WITH_EXPLICIT_FUNCTION("457528 CookieMonster::OnLoaded 2")); // Invoke the task queue of cookie request. InvokeQueue(); } @@ -1955,7 +1980,9 @@ histogram_cookie_deletion_cause_->Add(deletion_cause); CanonicalCookie* cc = it->second; - VLOG(kVlogSetCookies) << "InternalDeleteCookie() cc: " << cc->DebugString(); + VLOG(kVlogSetCookies) << "InternalDeleteCookie()" + << ", cause:" << deletion_cause + << ", cc: " << cc->DebugString(); if ((cc->IsPersistent() || persist_session_cookies_) && store_.get() && sync_to_store) @@ -2081,6 +2108,9 @@ int CookieMonster::GarbageCollectExpired(const Time& current, const CookieMapItPair& itpair, CookieItVector* cookie_its) { + // TODO(xiyuan): Remove the log after http://crbug.com/449816. + VLOG(kVlogSetCookies) << "CookieMonster::GarbageCollectExpired"; + if (keep_expired_cookies_) return 0; @@ -2106,6 +2136,9 @@ DeletionCause cause, CookieItVector::iterator it_begin, CookieItVector::iterator it_end) { + // TODO(xiyuan): Remove the log after http://crbug.com/449816. + VLOG(kVlogSetCookies) << "CookieMonster::GarbageCollectDeleteRange"; + for (CookieItVector::iterator it = it_begin; it != it_end; it++) { histogram_evicted_last_access_minutes_->Add( (current - (*it)->second->LastAccessDate()).InMinutes());
diff --git a/net/http/http_proxy_client_socket_pool.cc b/net/http/http_proxy_client_socket_pool.cc index 17e9f06..ff5fdf9f 100644 --- a/net/http/http_proxy_client_socket_pool.cc +++ b/net/http/http_proxy_client_socket_pool.cc
@@ -7,6 +7,7 @@ #include <algorithm> #include "base/compiler_specific.h" +#include "base/profiler/scoped_tracker.h" #include "base/time/time.h" #include "base/values.h" #include "net/base/load_flags.h" @@ -126,6 +127,10 @@ } void HttpProxyConnectJob::OnIOComplete(int result) { + // TODO(pkasting): Remove ScopedTracker below once crbug.com/455884 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "455884 HttpProxyConnectJob::OnIOComplete")); int rv = DoLoop(result); if (rv != ERR_IO_PENDING) { NotifyProxyDelegateOfCompletion(rv);
diff --git a/net/http/http_stream_factory_impl.cc b/net/http/http_stream_factory_impl.cc index dab8bc8..0397aca 100644 --- a/net/http/http_stream_factory_impl.cc +++ b/net/http/http_stream_factory_impl.cc
@@ -105,9 +105,6 @@ request->AttachJob(alternate_job); alternate_job->MarkAsAlternate(alternative_service); - // Never share connection with other jobs for FTP requests. - DCHECK(!request_info.url.SchemeIs("ftp")); - job->WaitFor(alternate_job); // Make sure to wait until we call WaitFor(), before starting // |alternate_job|, otherwise |alternate_job| will not notify |job|
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc index 78f4eed..9efc4acf 100644 --- a/net/http/http_stream_factory_impl_job.cc +++ b/net/http/http_stream_factory_impl_job.cc
@@ -436,6 +436,10 @@ } void HttpStreamFactoryImpl::Job::OnIOComplete(int result) { + // TODO(pkasting): Remove ScopedTracker below once crbug.com/455884 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "455884 HttpStreamFactoryImpl::Job::OnIOComplete")); RunLoop(result); }
diff --git a/net/proxy/proxy_resolver_v8_tracing.cc b/net/proxy/proxy_resolver_v8_tracing.cc index 3ad166c..230b7caf 100644 --- a/net/proxy/proxy_resolver_v8_tracing.cc +++ b/net/proxy/proxy_resolver_v8_tracing.cc
@@ -6,7 +6,6 @@ #include "base/bind.h" #include "base/message_loop/message_loop_proxy.h" -#include "base/profiler/scoped_tracker.h" #include "base/strings/stringprintf.h" #include "base/synchronization/cancellation_flag.h" #include "base/synchronization/waitable_event.h" @@ -956,11 +955,6 @@ net_log_(net_log), num_outstanding_callbacks_(0), on_load_state_changed_(on_load_state_changed) { - // TODO(eroman): Remove once crbug.com/454983 is fixed. - tracked_objects::ScopedTracker tracking_profile( - FROM_HERE_WITH_EXPLICIT_FUNCTION( - "454983 ProxyResolverV8Tracing::ProxyResolverV8Tracing")); - DCHECK(host_resolver); // Start up the thread. thread_.reset(new base::Thread("Proxy resolver"));
diff --git a/net/server/web_socket_encoder.cc b/net/server/web_socket_encoder.cc index 8e1681c..e35f759 100644 --- a/net/server/web_socket_encoder.cc +++ b/net/server/web_socket_encoder.cc
@@ -251,8 +251,7 @@ return; WebSocketExtensionParser parser; - parser.Parse(header_value); - if (parser.has_error()) + if (!parser.Parse(header_value)) return; const std::vector<WebSocketExtension>& extensions = parser.extensions(); // TODO(tyoshino): Fail if this method is used for parsing a response and
diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc index 0bc0056b8..f6e9671 100644 --- a/net/socket/client_socket_pool_base.cc +++ b/net/socket/client_socket_pool_base.cc
@@ -8,6 +8,7 @@ #include "base/format_macros.h" #include "base/logging.h" #include "base/message_loop/message_loop.h" +#include "base/profiler/scoped_tracker.h" #include "base/stl_util.h" #include "base/strings/string_util.h" #include "base/time/time.h" @@ -1127,6 +1128,10 @@ void ClientSocketPoolBaseHelper::InvokeUserCallback( ClientSocketHandle* handle) { + // TODO(pkasting): Remove ScopedTracker below once crbug.com/455884 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "455884 ClientSocketPoolBaseHelper::InvokeUserCallback")); PendingCallbackMap::iterator it = pending_callback_map_.find(handle); // Exit if the request has already been cancelled.
diff --git a/net/socket/socks_client_socket_pool.cc b/net/socket/socks_client_socket_pool.cc index ee613ac4..953c0c4 100644 --- a/net/socket/socks_client_socket_pool.cc +++ b/net/socket/socks_client_socket_pool.cc
@@ -6,6 +6,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/profiler/scoped_tracker.h" #include "base/time/time.h" #include "base/values.h" #include "net/base/net_errors.h" @@ -76,6 +77,9 @@ } void SOCKSConnectJob::OnIOComplete(int result) { + // TODO(pkasting): Remove ScopedTracker below once crbug.com/455884 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION("455884 SOCKSConnectJob::OnIOComplete")); int rv = DoLoop(result); if (rv != ERR_IO_PENDING) NotifyDelegateOfCompletion(rv); // Deletes |this|
diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc index 29f52a1bc..e6c770c 100644 --- a/net/socket/ssl_client_socket_pool.cc +++ b/net/socket/ssl_client_socket_pool.cc
@@ -166,6 +166,9 @@ } void SSLConnectJob::OnIOComplete(int result) { + // TODO(pkasting): Remove ScopedTracker below once crbug.com/455884 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION("455884 SSLConnectJob::OnIOComplete")); int rv = DoLoop(result); if (rv != ERR_IO_PENDING) NotifyDelegateOfCompletion(rv); // Deletes |this|.
diff --git a/net/url_request/url_fetcher_impl_unittest.cc b/net/url_request/url_fetcher_impl_unittest.cc index b545162..9b744788 100644 --- a/net/url_request/url_fetcher_impl_unittest.cc +++ b/net/url_request/url_fetcher_impl_unittest.cc
@@ -10,6 +10,7 @@ #include "base/bind.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" +#include "base/macros.h" #include "base/message_loop/message_loop_proxy.h" #include "base/path_service.h" #include "base/run_loop.h" @@ -64,24 +65,34 @@ // Can only be used once. class WaitingURLFetcherDelegate : public URLFetcherDelegate { public: - WaitingURLFetcherDelegate() : fetcher_(nullptr) {} + WaitingURLFetcherDelegate() {} - void StartFetcherAndWait(URLFetcher* fetcher) { - EXPECT_FALSE(fetcher_); - fetcher_ = fetcher; + // Creates a URLFetcher that runs network tasks on the current message loop. + void CreateFetcherWithContext(const GURL& url, + URLFetcher::RequestType request_type, + net::URLRequestContext* context) { + fetcher_.reset(new URLFetcherImpl(url, request_type, this)); + fetcher_->SetRequestContext(new TrivialURLRequestContextGetter( + context, base::MessageLoopProxy::current())); + } + + URLFetcher* fetcher() const { return fetcher_.get(); } + + void StartFetcherAndWait() { fetcher_->Start(); run_loop_.Run(); - fetcher_ = nullptr; } void OnURLFetchComplete(const URLFetcher* source) override { - EXPECT_EQ(fetcher_, source); + EXPECT_EQ(fetcher_.get(), source); run_loop_.Quit(); } private: - URLFetcher* fetcher_; + scoped_ptr<URLFetcherImpl> fetcher_; base::RunLoop run_loop_; + + DISALLOW_COPY_AND_ASSIGN(WaitingURLFetcherDelegate); }; class ThrottlingTestURLRequestContext : public TestURLRequestContext { @@ -350,70 +361,6 @@ int64 number_of_chunks_added_; }; -// Version of URLFetcherTest that tests headers. -class URLFetcherHeadersTest : public URLFetcherTest { - public: - // URLFetcherDelegate: - void OnURLFetchComplete(const URLFetcher* source) override; -}; - -// Version of URLFetcherTest that tests SocketAddress. -class URLFetcherSocketAddressTest : public URLFetcherTest { - public: - // URLFetcherDelegate: - void OnURLFetchComplete(const URLFetcher* source) override; - - protected: - std::string expected_host_; - uint16 expected_port_; -}; - -// Version of URLFetcherTest that tests stopping on a redirect. -class URLFetcherStopOnRedirectTest : public URLFetcherTest { - public: - URLFetcherStopOnRedirectTest(); - ~URLFetcherStopOnRedirectTest() override; - - // URLFetcherTest: - void CreateFetcher(const GURL& url) override; - - // URLFetcherDelegate: - void OnURLFetchComplete(const URLFetcher* source) override; - - protected: - // The URL we should be redirected to. - static const char* kRedirectTarget; - - bool callback_called_; // Set to true in OnURLFetchComplete(). -}; - -// Version of URLFetcherTest that tests overload protection. -class URLFetcherProtectTest : public URLFetcherTest { - public: - // URLFetcherTest: - void CreateFetcher(const GURL& url) override; - - // URLFetcherDelegate: - void OnURLFetchComplete(const URLFetcher* source) override; - - private: - Time start_time_; -}; - -// Version of URLFetcherTest that tests overload protection, when responses -// passed through. -class URLFetcherProtectTestPassedThrough : public URLFetcherTest { - public: - // URLFetcherTest: - void CreateFetcher(const GURL& url) override; - - // URLFetcherDelegate: - void OnURLFetchComplete(const URLFetcher* source) override; - - private: - Time start_time_; -}; - // Version of URLFetcherTest that tests bad HTTPS requests. class URLFetcherBadHTTPSTest : public URLFetcherTest { public: @@ -619,121 +566,6 @@ } } -void URLFetcherHeadersTest::OnURLFetchComplete( - const URLFetcher* source) { - std::string header; - EXPECT_TRUE(source->GetResponseHeaders()->GetNormalizedHeader("cache-control", - &header)); - EXPECT_EQ("private", header); - URLFetcherTest::OnURLFetchComplete(source); -} - -void URLFetcherSocketAddressTest::OnURLFetchComplete( - const URLFetcher* source) { - EXPECT_EQ("127.0.0.1", source->GetSocketAddress().host()); - EXPECT_EQ(expected_port_, source->GetSocketAddress().port()); - URLFetcherTest::OnURLFetchComplete(source); -} - -// static -const char* URLFetcherStopOnRedirectTest::kRedirectTarget = - "http://redirect.target.com"; - -URLFetcherStopOnRedirectTest::URLFetcherStopOnRedirectTest() - : callback_called_(false) { -} - -URLFetcherStopOnRedirectTest::~URLFetcherStopOnRedirectTest() { -} - -void URLFetcherStopOnRedirectTest::CreateFetcher(const GURL& url) { - fetcher_ = new URLFetcherImpl(url, URLFetcher::GET, this); - fetcher_->SetRequestContext(new ThrottlingTestURLRequestContextGetter( - io_message_loop_proxy().get(), request_context())); - fetcher_->SetStopOnRedirect(true); - fetcher_->Start(); -} - -void URLFetcherStopOnRedirectTest::OnURLFetchComplete( - const URLFetcher* source) { - callback_called_ = true; - EXPECT_EQ(GURL(kRedirectTarget), source->GetURL()); - EXPECT_EQ(URLRequestStatus::CANCELED, source->GetStatus().status()); - EXPECT_EQ(ERR_ABORTED, source->GetStatus().error()); - EXPECT_EQ(301, source->GetResponseCode()); - CleanupAfterFetchComplete(); -} - -void URLFetcherProtectTest::CreateFetcher(const GURL& url) { - fetcher_ = new URLFetcherImpl(url, URLFetcher::GET, this); - fetcher_->SetRequestContext(new ThrottlingTestURLRequestContextGetter( - io_message_loop_proxy().get(), request_context())); - start_time_ = Time::Now(); - fetcher_->SetMaxRetriesOn5xx(11); - fetcher_->Start(); -} - -void URLFetcherProtectTest::OnURLFetchComplete(const URLFetcher* source) { - const TimeDelta one_second = TimeDelta::FromMilliseconds(1000); - if (source->GetResponseCode() >= 500) { - // Now running ServerUnavailable test. - // It takes more than 1 second to finish all 11 requests. - EXPECT_TRUE(Time::Now() - start_time_ >= one_second); - EXPECT_TRUE(source->GetStatus().is_success()); - std::string data; - EXPECT_TRUE(source->GetResponseAsString(&data)); - EXPECT_FALSE(data.empty()); - CleanupAfterFetchComplete(); - } else { - // Now running Overload test. - static int count = 0; - count++; - if (count < 20) { - fetcher_->SetRequestContext(new ThrottlingTestURLRequestContextGetter( - io_message_loop_proxy().get(), request_context())); - fetcher_->Start(); - } else { - // We have already sent 20 requests continuously. And we expect that - // it takes more than 1 second due to the overload protection settings. - EXPECT_TRUE(Time::Now() - start_time_ >= one_second); - URLFetcherTest::OnURLFetchComplete(source); - } - } -} - -void URLFetcherProtectTestPassedThrough::CreateFetcher(const GURL& url) { - fetcher_ = new URLFetcherImpl(url, URLFetcher::GET, this); - fetcher_->SetRequestContext(new ThrottlingTestURLRequestContextGetter( - io_message_loop_proxy().get(), request_context())); - fetcher_->SetAutomaticallyRetryOn5xx(false); - start_time_ = Time::Now(); - fetcher_->SetMaxRetriesOn5xx(11); - fetcher_->Start(); -} - -void URLFetcherProtectTestPassedThrough::OnURLFetchComplete( - const URLFetcher* source) { - const TimeDelta one_minute = TimeDelta::FromMilliseconds(60000); - if (source->GetResponseCode() >= 500) { - // Now running ServerUnavailable test. - // It should get here on the first attempt, so almost immediately and - // *not* to attempt to execute all 11 requests (2.5 minutes). - EXPECT_TRUE(Time::Now() - start_time_ < one_minute); - EXPECT_TRUE(source->GetStatus().is_success()); - // Check that suggested back off time is bigger than 0. - EXPECT_GT(fetcher_->GetBackoffDelay().InMicroseconds(), 0); - std::string data; - EXPECT_TRUE(source->GetResponseAsString(&data)); - EXPECT_FALSE(data.empty()); - } else { - // We should not get here! - ADD_FAILURE(); - } - - CleanupAfterFetchComplete(); -} - - URLFetcherBadHTTPSTest::URLFetcherBadHTTPSTest() { PathService::Get(base::DIR_SOURCE_ROOT, &cert_dir_); cert_dir_ = cert_dir_.AppendASCII("chrome"); @@ -1005,17 +837,16 @@ const char kUploadData[] = "bobsyeruncle"; WaitingURLFetcherDelegate delegate; - URLFetcherImpl fetcher(test_server_->GetURL("echo"), URLFetcher::POST, - &delegate); - fetcher.SetRequestContext(new TrivialURLRequestContextGetter( - request_context(), base::MessageLoopProxy::current())); - fetcher.SetUploadData("application/x-www-form-urlencoded", kUploadData); - delegate.StartFetcherAndWait(&fetcher); + delegate.CreateFetcherWithContext(test_server_->GetURL("echo"), + URLFetcher::POST, request_context()); + delegate.fetcher()->SetUploadData("application/x-www-form-urlencoded", + kUploadData); + delegate.StartFetcherAndWait(); - EXPECT_TRUE(fetcher.GetStatus().is_success()); - EXPECT_EQ(200, fetcher.GetResponseCode()); + EXPECT_TRUE(delegate.fetcher()->GetStatus().is_success()); + EXPECT_EQ(200, delegate.fetcher()->GetResponseCode()); std::string data; - EXPECT_TRUE(fetcher.GetResponseAsString(&data)); + ASSERT_TRUE(delegate.fetcher()->GetResponseAsString(&data)); EXPECT_EQ(kUploadData, data); } @@ -1023,17 +854,16 @@ const char kUploadData[] = ""; WaitingURLFetcherDelegate delegate; - URLFetcherImpl fetcher(test_server_->GetURL("echo"), URLFetcher::POST, - &delegate); - fetcher.SetRequestContext(new TrivialURLRequestContextGetter( - request_context(), base::MessageLoopProxy::current())); - fetcher.SetUploadData("application/x-www-form-urlencoded", kUploadData); - delegate.StartFetcherAndWait(&fetcher); + delegate.CreateFetcherWithContext(test_server_->GetURL("echo"), + URLFetcher::POST, request_context()); + delegate.fetcher()->SetUploadData("application/x-www-form-urlencoded", + kUploadData); + delegate.StartFetcherAndWait(); - EXPECT_TRUE(fetcher.GetStatus().is_success()); - EXPECT_EQ(200, fetcher.GetResponseCode()); + EXPECT_TRUE(delegate.fetcher()->GetStatus().is_success()); + EXPECT_EQ(200, delegate.fetcher()->GetResponseCode()); std::string data; - EXPECT_TRUE(fetcher.GetResponseAsString(&data)); + ASSERT_TRUE(delegate.fetcher()->GetResponseAsString(&data)); EXPECT_EQ(kUploadData, data); } @@ -1041,21 +871,20 @@ base::FilePath upload_path = GetUploadFileTestPath(); WaitingURLFetcherDelegate delegate; - URLFetcherImpl fetcher(test_server_->GetURL("echo"), URLFetcher::POST, - &delegate); - fetcher.SetRequestContext(new TrivialURLRequestContextGetter( - request_context(), base::MessageLoopProxy::current())); - fetcher.SetUploadFilePath("application/x-www-form-urlencoded", upload_path, 0, - kuint64max, base::MessageLoopProxy::current()); - delegate.StartFetcherAndWait(&fetcher); + delegate.CreateFetcherWithContext(test_server_->GetURL("echo"), + URLFetcher::POST, request_context()); + delegate.fetcher()->SetUploadFilePath("application/x-www-form-urlencoded", + upload_path, 0, kuint64max, + base::MessageLoopProxy::current()); + delegate.StartFetcherAndWait(); - EXPECT_TRUE(fetcher.GetStatus().is_success()); - EXPECT_EQ(200, fetcher.GetResponseCode()); + EXPECT_TRUE(delegate.fetcher()->GetStatus().is_success()); + EXPECT_EQ(200, delegate.fetcher()->GetResponseCode()); std::string expected; ASSERT_TRUE(base::ReadFileToString(upload_path, &expected)); std::string data; - EXPECT_TRUE(fetcher.GetResponseAsString(&data)); + ASSERT_TRUE(delegate.fetcher()->GetResponseAsString(&data)); EXPECT_EQ(expected, data); } @@ -1065,61 +894,55 @@ base::FilePath upload_path = GetUploadFileTestPath(); WaitingURLFetcherDelegate delegate; - URLFetcherImpl fetcher(test_server_->GetURL("echo"), URLFetcher::POST, - &delegate); - fetcher.SetRequestContext(new TrivialURLRequestContextGetter( - request_context(), base::MessageLoopProxy::current())); - fetcher.SetUploadFilePath("application/x-www-form-urlencoded", upload_path, - kRangeStart, kRangeLength, - base::MessageLoopProxy::current()); - delegate.StartFetcherAndWait(&fetcher); + delegate.CreateFetcherWithContext(test_server_->GetURL("echo"), + URLFetcher::POST, request_context()); + delegate.fetcher()->SetUploadFilePath("application/x-www-form-urlencoded", + upload_path, kRangeStart, kRangeLength, + base::MessageLoopProxy::current()); + delegate.StartFetcherAndWait(); - EXPECT_TRUE(fetcher.GetStatus().is_success()); - EXPECT_EQ(200, fetcher.GetResponseCode()); + EXPECT_TRUE(delegate.fetcher()->GetStatus().is_success()); + EXPECT_EQ(200, delegate.fetcher()->GetResponseCode()); std::string expected; ASSERT_TRUE(base::ReadFileToString(upload_path, &expected)); std::string data; - EXPECT_TRUE(fetcher.GetResponseAsString(&data)); + ASSERT_TRUE(delegate.fetcher()->GetResponseAsString(&data)); EXPECT_EQ(expected.substr(kRangeStart, kRangeLength), data); } TEST_F(URLFetcherTest, PostWithUploadStreamFactory) { WaitingURLFetcherDelegate delegate; - URLFetcherImpl fetcher(test_server_->GetURL("echo"), URLFetcher::POST, - &delegate); - fetcher.SetRequestContext(new TrivialURLRequestContextGetter( - request_context(), base::MessageLoopProxy::current())); - fetcher.SetUploadStreamFactory( + delegate.CreateFetcherWithContext(test_server_->GetURL("echo"), + URLFetcher::POST, request_context()); + delegate.fetcher()->SetUploadStreamFactory( "text/plain", base::Bind(&URLFetcherTest::CreateUploadStream, base::Unretained(this))); - delegate.StartFetcherAndWait(&fetcher); + delegate.StartFetcherAndWait(); - EXPECT_TRUE(fetcher.GetStatus().is_success()); - EXPECT_EQ(200, fetcher.GetResponseCode()); + EXPECT_TRUE(delegate.fetcher()->GetStatus().is_success()); + EXPECT_EQ(200, delegate.fetcher()->GetResponseCode()); std::string data; - EXPECT_TRUE(fetcher.GetResponseAsString(&data)); + ASSERT_TRUE(delegate.fetcher()->GetResponseAsString(&data)); EXPECT_EQ(kCreateUploadStreamBody, data); EXPECT_EQ(1u, num_upload_streams_created()); } TEST_F(URLFetcherTest, PostWithUploadStreamFactoryAndRetries) { WaitingURLFetcherDelegate delegate; - URLFetcherImpl fetcher(test_server_->GetURL("echo?status=500"), - URLFetcher::POST, &delegate); - fetcher.SetRequestContext(new TrivialURLRequestContextGetter( - request_context(), base::MessageLoopProxy::current())); - fetcher.SetAutomaticallyRetryOn5xx(true); - fetcher.SetMaxRetriesOn5xx(1); - fetcher.SetUploadStreamFactory( + delegate.CreateFetcherWithContext(test_server_->GetURL("echo?status=500"), + URLFetcher::POST, request_context()); + delegate.fetcher()->SetAutomaticallyRetryOn5xx(true); + delegate.fetcher()->SetMaxRetriesOn5xx(1); + delegate.fetcher()->SetUploadStreamFactory( "text/plain", base::Bind(&URLFetcherTest::CreateUploadStream, base::Unretained(this))); - delegate.StartFetcherAndWait(&fetcher); + delegate.StartFetcherAndWait(); - EXPECT_TRUE(fetcher.GetStatus().is_success()); - EXPECT_EQ(500, fetcher.GetResponseCode()); + EXPECT_TRUE(delegate.fetcher()->GetStatus().is_success()); + EXPECT_EQ(500, delegate.fetcher()->GetResponseCode()); std::string data; - EXPECT_TRUE(fetcher.GetResponseAsString(&data)); + ASSERT_TRUE(delegate.fetcher()->GetResponseAsString(&data)); EXPECT_EQ(kCreateUploadStreamBody, data); EXPECT_EQ(2u, num_upload_streams_created()); } @@ -1155,97 +978,153 @@ base::MessageLoop::current()->Run(); } -TEST_F(URLFetcherHeadersTest, Headers) { - CreateFetcher(test_server_->GetURL("set-header?cache-control: private")); - base::MessageLoop::current()->Run(); - // The actual tests are in the URLFetcherHeadersTest fixture. +TEST_F(URLFetcherTest, Headers) { + WaitingURLFetcherDelegate delegate; + delegate.CreateFetcherWithContext( + test_server_->GetURL("set-header?cache-control: private"), + URLFetcher::GET, request_context()); + delegate.StartFetcherAndWait(); + + EXPECT_TRUE(delegate.fetcher()->GetStatus().is_success()); + EXPECT_EQ(200, delegate.fetcher()->GetResponseCode()); + std::string header; + ASSERT_TRUE(delegate.fetcher()->GetResponseHeaders()->GetNormalizedHeader( + "cache-control", &header)); + EXPECT_EQ("private", header); } -TEST_F(URLFetcherSocketAddressTest, SocketAddress) { - expected_port_ = test_server_->host_port_pair().port(); +TEST_F(URLFetcherTest, SocketAddress) { + WaitingURLFetcherDelegate delegate; + delegate.CreateFetcherWithContext(test_server_->GetURL("defaultresponse"), + URLFetcher::GET, request_context()); + delegate.StartFetcherAndWait(); - CreateFetcher(test_server_->GetURL("defaultresponse")); - base::MessageLoop::current()->Run(); - // The actual tests are in the URLFetcherSocketAddressTest fixture. + EXPECT_TRUE(delegate.fetcher()->GetStatus().is_success()); + EXPECT_EQ(200, delegate.fetcher()->GetResponseCode()); + EXPECT_EQ(test_server_->host_port_pair().port(), + delegate.fetcher()->GetSocketAddress().port()); + EXPECT_EQ(test_server_->host_port_pair().host(), + delegate.fetcher()->GetSocketAddress().host()); } -TEST_F(URLFetcherStopOnRedirectTest, StopOnRedirect) { - CreateFetcher( - test_server_->GetURL(std::string("server-redirect?") + kRedirectTarget)); - base::MessageLoop::current()->Run(); - EXPECT_TRUE(callback_called_); +TEST_F(URLFetcherTest, StopOnRedirect) { + const char kRedirectTarget[] = "http://redirect.target.com"; + + WaitingURLFetcherDelegate delegate; + delegate.CreateFetcherWithContext( + test_server_->GetURL(std::string("server-redirect?") + kRedirectTarget), + URLFetcher::GET, request_context()); + delegate.fetcher()->SetStopOnRedirect(true); + delegate.StartFetcherAndWait(); + + EXPECT_EQ(GURL(kRedirectTarget), delegate.fetcher()->GetURL()); + EXPECT_EQ(URLRequestStatus::CANCELED, + delegate.fetcher()->GetStatus().status()); + EXPECT_EQ(ERR_ABORTED, delegate.fetcher()->GetStatus().error()); + EXPECT_EQ(301, delegate.fetcher()->GetResponseCode()); } -TEST_F(URLFetcherProtectTest, Overload) { +TEST_F(URLFetcherTest, ThrottleOnRepeatedFetches) { + base::Time start_time = Time::Now(); GURL url(test_server_->GetURL("defaultresponse")); // Registers an entry for test url. It only allows 3 requests to be sent // in 200 milliseconds. - scoped_refptr<URLRequestThrottlerEntry> entry( - new URLRequestThrottlerEntry(request_context()->throttler_manager(), - std::string(), - 200, - 3, - 1, - 2.0, - 0.0, - 256)); + scoped_refptr<URLRequestThrottlerEntry> entry(new URLRequestThrottlerEntry( + request_context()->throttler_manager(), std::string() /* url_id */, + 200 /* sliding_window_period_ms */, 3 /* max_send_threshold */, + 1 /* initial_backoff_ms */, 2.0 /* multiply_factor */, + 0.0 /* jitter_factor */, 256 /* maximum_backoff_ms */)); + request_context()->throttler_manager() ->OverrideEntryForTests(url, entry.get()); - CreateFetcher(url); + for (int i = 0; i < 20; ++i) { + WaitingURLFetcherDelegate delegate; + delegate.CreateFetcherWithContext(url, URLFetcher::GET, request_context()); + delegate.StartFetcherAndWait(); - base::MessageLoop::current()->Run(); + EXPECT_TRUE(delegate.fetcher()->GetStatus().is_success()); + EXPECT_EQ(200, delegate.fetcher()->GetResponseCode()); + } + + // 20 requests were sent. Due to throttling, they should have collectively + // taken over 1 second. + EXPECT_GE(Time::Now() - start_time, base::TimeDelta::FromSeconds(1)); } -TEST_F(URLFetcherProtectTest, ServerUnavailable) { +TEST_F(URLFetcherTest, ThrottleOn5xxRetries) { + base::Time start_time = Time::Now(); GURL url(test_server_->GetURL("files/server-unavailable.html")); // Registers an entry for test url. The backoff time is calculated by: // new_backoff = 2.0 * old_backoff + 0 // and maximum backoff time is 256 milliseconds. // Maximum retries allowed is set to 11. - scoped_refptr<URLRequestThrottlerEntry> entry( - new URLRequestThrottlerEntry(request_context()->throttler_manager(), - std::string(), - 200, - 3, - 1, - 2.0, - 0.0, - 256)); + scoped_refptr<URLRequestThrottlerEntry> entry(new URLRequestThrottlerEntry( + request_context()->throttler_manager(), std::string() /* url_id */, + 200 /* sliding_window_period_ms */, 3 /* max_send_threshold */, + 1 /* initial_backoff_ms */, 2.0 /* multiply_factor */, + 0.0 /* jitter_factor */, 256 /* maximum_backoff_ms */)); request_context()->throttler_manager() ->OverrideEntryForTests(url, entry.get()); - CreateFetcher(url); + request_context()->throttler_manager()->OverrideEntryForTests(url, + entry.get()); - base::MessageLoop::current()->Run(); + WaitingURLFetcherDelegate delegate; + delegate.CreateFetcherWithContext(url, URLFetcher::GET, request_context()); + delegate.fetcher()->SetAutomaticallyRetryOn5xx(true); + delegate.fetcher()->SetMaxRetriesOn5xx(11); + delegate.StartFetcherAndWait(); + + EXPECT_TRUE(delegate.fetcher()->GetStatus().is_success()); + EXPECT_EQ(503, delegate.fetcher()->GetResponseCode()); + std::string data; + ASSERT_TRUE(delegate.fetcher()->GetResponseAsString(&data)); + EXPECT_FALSE(data.empty()); + + // The request should have been retried 11 times (12 times including the first + // attempt). Due to throttling, they should have collectively taken over 1 + // second. + EXPECT_GE(Time::Now() - start_time, base::TimeDelta::FromSeconds(1)); } -TEST_F(URLFetcherProtectTestPassedThrough, ServerUnavailablePropagateResponse) { +// Tests overload protection, when responses passed through. +TEST_F(URLFetcherTest, ProtectTestPassedThrough) { + base::Time start_time = Time::Now(); GURL url(test_server_->GetURL("files/server-unavailable.html")); // Registers an entry for test url. The backoff time is calculated by: // new_backoff = 2.0 * old_backoff + 0 // and maximum backoff time is 150000 milliseconds. // Maximum retries allowed is set to 11. - scoped_refptr<URLRequestThrottlerEntry> entry( - new URLRequestThrottlerEntry(request_context()->throttler_manager(), - std::string(), - 200, - 3, - 100, - 2.0, - 0.0, - 150000)); + scoped_refptr<URLRequestThrottlerEntry> entry(new URLRequestThrottlerEntry( + request_context()->throttler_manager(), std::string() /* url_id */, + 200 /* sliding_window_period_ms */, 3 /* max_send_threshold */, + 10000 /* initial_backoff_ms */, 2.0 /* multiply_factor */, + 0.0 /* jitter_factor */, 150000 /* maximum_backoff_ms */)); // Total time if *not* for not doing automatic backoff would be 150s. // In reality it should be "as soon as server responds". request_context()->throttler_manager() ->OverrideEntryForTests(url, entry.get()); - CreateFetcher(url); + WaitingURLFetcherDelegate delegate; + delegate.CreateFetcherWithContext(url, URLFetcher::GET, request_context()); + delegate.fetcher()->SetAutomaticallyRetryOn5xx(false); + delegate.fetcher()->SetMaxRetriesOn5xx(11); + delegate.StartFetcherAndWait(); - base::MessageLoop::current()->Run(); + EXPECT_TRUE(delegate.fetcher()->GetStatus().is_success()); + EXPECT_EQ(503, delegate.fetcher()->GetResponseCode()); + std::string data; + ASSERT_TRUE(delegate.fetcher()->GetResponseAsString(&data)); + EXPECT_FALSE(data.empty()); + EXPECT_GT(delegate.fetcher()->GetBackoffDelay().InMicroseconds(), 0); + + // The request should not have been retried at all. If it had attempted all + // 11 retries, that should have taken 2.5 minutes. + EXPECT_TRUE(Time::Now() - start_time < TimeDelta::FromMinutes(1)); } TEST_F(URLFetcherBadHTTPSTest, BadHTTPSTest) {
diff --git a/net/websockets/websocket_basic_handshake_stream.cc b/net/websockets/websocket_basic_handshake_stream.cc index a4a7d7b5..7bb34a3 100644 --- a/net/websockets/websocket_basic_handshake_stream.cc +++ b/net/websockets/websocket_basic_handshake_stream.cc
@@ -315,8 +315,7 @@ while (headers->EnumerateHeader(&state, websockets::kSecWebSocketExtensions, &header_value)) { WebSocketExtensionParser parser; - parser.Parse(header_value); - if (parser.has_error()) { + if (!parser.Parse(header_value)) { // TODO(yhirano) Set appropriate failure message. *failure_message = "'Sec-WebSocket-Extensions' header value is "
diff --git a/net/websockets/websocket_extension_parser.cc b/net/websockets/websocket_extension_parser.cc index 109d330..b737d5e 100644 --- a/net/websockets/websocket_extension_parser.cc +++ b/net/websockets/websocket_extension_parser.cc
@@ -12,100 +12,102 @@ WebSocketExtensionParser::~WebSocketExtensionParser() {} -void WebSocketExtensionParser::Parse(const char* data, size_t size) { +bool WebSocketExtensionParser::Parse(const char* data, size_t size) { current_ = data; end_ = data + size; - has_error_ = false; extensions_.clear(); + bool failed = false; + while (true) { WebSocketExtension extension; - ConsumeExtension(&extension); - if (has_error_) + if (!ConsumeExtension(&extension)) { + failed = true; break; + } extensions_.push_back(extension); ConsumeSpaces(); - DCHECK(!has_error_); if (!ConsumeIfMatch(',')) { break; } } - has_error_ = has_error_ || current_ != end_; - if (has_error_) - extensions_.clear(); + if (!failed && current_ == end_) + return true; + + extensions_.clear(); + return false; } -void WebSocketExtensionParser::Consume(char c) { - DCHECK(!has_error_); +bool WebSocketExtensionParser::Consume(char c) { ConsumeSpaces(); - DCHECK(!has_error_); if (current_ == end_ || c != current_[0]) { - has_error_ = true; - return; + return false; } ++current_; + return true; } -void WebSocketExtensionParser::ConsumeExtension(WebSocketExtension* extension) { - DCHECK(!has_error_); +bool WebSocketExtensionParser::ConsumeExtension(WebSocketExtension* extension) { base::StringPiece name; - ConsumeToken(&name); - if (has_error_) return; + if (!ConsumeToken(&name)) + return false; *extension = WebSocketExtension(name.as_string()); while (ConsumeIfMatch(';')) { WebSocketExtension::Parameter parameter((std::string())); - ConsumeExtensionParameter(¶meter); - if (has_error_) return; + if (!ConsumeExtensionParameter(¶meter)) + return false; extension->Add(parameter); } + + return true; } -void WebSocketExtensionParser::ConsumeExtensionParameter( +bool WebSocketExtensionParser::ConsumeExtensionParameter( WebSocketExtension::Parameter* parameter) { - DCHECK(!has_error_); base::StringPiece name, value; std::string value_string; - ConsumeToken(&name); - if (has_error_) return; + if (!ConsumeToken(&name)) + return false; + if (!ConsumeIfMatch('=')) { *parameter = WebSocketExtension::Parameter(name.as_string()); - return; + return true; } if (Lookahead('\"')) { - ConsumeQuotedToken(&value_string); + if (!ConsumeQuotedToken(&value_string)) + return false; } else { - ConsumeToken(&value); + if (!ConsumeToken(&value)) + return false; value_string = value.as_string(); } - if (has_error_) return; *parameter = WebSocketExtension::Parameter(name.as_string(), value_string); + return true; } -void WebSocketExtensionParser::ConsumeToken(base::StringPiece* token) { - DCHECK(!has_error_); +bool WebSocketExtensionParser::ConsumeToken(base::StringPiece* token) { ConsumeSpaces(); - DCHECK(!has_error_); const char* head = current_; while (current_ < end_ && !IsControl(current_[0]) && !IsSeparator(current_[0])) ++current_; if (current_ == head) { - has_error_ = true; - return; + return false; } *token = base::StringPiece(head, current_ - head); + return true; } -void WebSocketExtensionParser::ConsumeQuotedToken(std::string* token) { - DCHECK(!has_error_); - Consume('"'); - if (has_error_) return; +bool WebSocketExtensionParser::ConsumeQuotedToken(std::string* token) { + if (!Consume('"')) + return false; + *token = ""; while (current_ < end_ && !IsControl(current_[0])) { if (UnconsumedBytes() >= 2 && current_[0] == '\\') { @@ -121,41 +123,34 @@ } } // We can't use Consume here because we don't want to consume spaces. - if (current_ < end_ && current_[0] == '"') - ++current_; - else - has_error_ = true; - has_error_ = has_error_ || token->empty(); + if (current_ >= end_ || current_[0] != '"') + return false; + + ++current_; + + return !token->empty(); } void WebSocketExtensionParser::ConsumeSpaces() { - DCHECK(!has_error_); while (current_ < end_ && (current_[0] == ' ' || current_[0] == '\t')) ++current_; return; } bool WebSocketExtensionParser::Lookahead(char c) { - DCHECK(!has_error_); const char* head = current_; - - Consume(c); - bool result = !has_error_; + bool result = Consume(c); current_ = head; - has_error_ = false; return result; } bool WebSocketExtensionParser::ConsumeIfMatch(char c) { - DCHECK(!has_error_); const char* head = current_; - - Consume(c); - if (has_error_) { + if (!Consume(c)) { current_ = head; - has_error_ = false; return false; } + return true; }
diff --git a/net/websockets/websocket_extension_parser.h b/net/websockets/websocket_extension_parser.h index 6b2e4dc..007040de 100644 --- a/net/websockets/websocket_extension_parser.h +++ b/net/websockets/websocket_extension_parser.h
@@ -8,6 +8,7 @@ #include <string> #include <vector> +#include "base/compiler_specific.h" #include "base/strings/string_piece.h" #include "net/base/net_export.h" #include "net/websockets/websocket_extension.h" @@ -23,28 +24,28 @@ // // There must be no newline characters in the input. LWS-concatenation must // have already been done before calling this method. - void Parse(const char* data, size_t size); - void Parse(const std::string& data) { - Parse(data.data(), data.size()); + // + // Returns true if the method was successful (no syntax error was found). + bool Parse(const char* data, size_t size); + bool Parse(const std::string& data) { + return Parse(data.data(), data.size()); } - // Returns true if the last Parse() method call encountered any syntax error. - bool has_error() const { return has_error_; } // Returns the result of the last Parse() method call. const std::vector<WebSocketExtension>& extensions() const { return extensions_; } private: - // TODO(tyoshino): Make the following methods return success/fail. - void Consume(char c); - void ConsumeExtension(WebSocketExtension* extension); - void ConsumeExtensionParameter(WebSocketExtension::Parameter* parameter); - void ConsumeToken(base::StringPiece* token); - void ConsumeQuotedToken(std::string* token); + WARN_UNUSED_RESULT bool Consume(char c); + WARN_UNUSED_RESULT bool ConsumeExtension(WebSocketExtension* extension); + WARN_UNUSED_RESULT bool ConsumeExtensionParameter( + WebSocketExtension::Parameter* parameter); + WARN_UNUSED_RESULT bool ConsumeToken(base::StringPiece* token); + WARN_UNUSED_RESULT bool ConsumeQuotedToken(std::string* token); void ConsumeSpaces(); - bool Lookahead(char c); - bool ConsumeIfMatch(char c); + WARN_UNUSED_RESULT bool Lookahead(char c); + WARN_UNUSED_RESULT bool ConsumeIfMatch(char c); size_t UnconsumedBytes() const { return end_ - current_; } static bool IsControl(char c); @@ -54,7 +55,6 @@ const char* current_; // The pointer of the end of the input string. const char* end_; - bool has_error_; std::vector<WebSocketExtension> extensions_; DISALLOW_COPY_AND_ASSIGN(WebSocketExtensionParser);
diff --git a/net/websockets/websocket_extension_parser_test.cc b/net/websockets/websocket_extension_parser_test.cc index 616f8ec..b0a2be9 100644 --- a/net/websockets/websocket_extension_parser_test.cc +++ b/net/websockets/websocket_extension_parser_test.cc
@@ -15,9 +15,8 @@ TEST(WebSocketExtensionParserTest, ParseEmpty) { WebSocketExtensionParser parser; - parser.Parse("", 0); + EXPECT_FALSE(parser.Parse("", 0)); - EXPECT_TRUE(parser.has_error()); EXPECT_EQ(0U, parser.extensions().size()); } @@ -25,9 +24,8 @@ WebSocketExtensionParser parser; WebSocketExtension expected("foo"); - parser.Parse("foo"); + EXPECT_TRUE(parser.Parse("foo")); - ASSERT_FALSE(parser.has_error()); ASSERT_EQ(1U, parser.extensions().size()); EXPECT_TRUE(expected.Equals(parser.extensions()[0])); } @@ -36,17 +34,14 @@ WebSocketExtensionParser parser; WebSocketExtension expected("foo"); - parser.Parse("foo"); - ASSERT_FALSE(parser.has_error()); + EXPECT_TRUE(parser.Parse("foo")); ASSERT_EQ(1U, parser.extensions().size()); EXPECT_TRUE(expected.Equals(parser.extensions()[0])); - parser.Parse(""); - EXPECT_TRUE(parser.has_error()); + EXPECT_FALSE(parser.Parse("")); EXPECT_EQ(0U, parser.extensions().size()); - parser.Parse("foo"); - ASSERT_FALSE(parser.has_error()); + EXPECT_TRUE(parser.Parse("foo")); ASSERT_EQ(1U, parser.extensions().size()); EXPECT_TRUE(expected.Equals(parser.extensions()[0])); } @@ -56,9 +51,8 @@ WebSocketExtension expected("foo"); expected.Add(WebSocketExtension::Parameter("bar")); - parser.Parse("\tfoo ; bar"); + EXPECT_TRUE(parser.Parse("\tfoo ; bar")); - ASSERT_FALSE(parser.has_error()); ASSERT_EQ(1U, parser.extensions().size()); EXPECT_TRUE(expected.Equals(parser.extensions()[0])); } @@ -68,9 +62,8 @@ WebSocketExtension expected("foo"); expected.Add(WebSocketExtension::Parameter("bar", "baz")); - parser.Parse("foo ; bar= baz\t"); + EXPECT_TRUE(parser.Parse("foo ; bar= baz\t")); - ASSERT_FALSE(parser.has_error()); ASSERT_EQ(1U, parser.extensions().size()); EXPECT_TRUE(expected.Equals(parser.extensions()[0])); } @@ -81,9 +74,8 @@ expected.Add(WebSocketExtension::Parameter("bar", "baz")); expected.Add(WebSocketExtension::Parameter("hoge", "fuga")); - parser.Parse("foo ; bar= baz;\t \thoge\t\t=fuga"); + EXPECT_TRUE(parser.Parse("foo ; bar= baz;\t \thoge\t\t=fuga")); - ASSERT_FALSE(parser.has_error()); ASSERT_EQ(1U, parser.extensions().size()); EXPECT_TRUE(expected.Equals(parser.extensions()[0])); } @@ -97,9 +89,8 @@ WebSocketExtension expected1("bar"); expected1.Add(WebSocketExtension::Parameter("beta", "y")); - parser.Parse(" foo ; alpha = x , bar ; beta = y "); + EXPECT_TRUE(parser.Parse(" foo ; alpha = x , bar ; beta = y ")); - ASSERT_FALSE(parser.has_error()); ASSERT_EQ(2U, parser.extensions().size()); EXPECT_TRUE(expected0.Equals(parser.extensions()[0])); @@ -113,6 +104,7 @@ "foo,", // second extension is incomplete (empty) "foo , ", // second extension is incomplete (space) "foo,;", // second extension is incomplete (semicolon) + "foo;, bar", // first extension is incomplete "fo\ao", // control in extension name "fo\x01o", // control in extension name "fo<o", // separator in extension name @@ -147,8 +139,7 @@ for (size_t i = 0; i < arraysize(patterns); ++i) { WebSocketExtensionParser parser; - parser.Parse(patterns[i]); - EXPECT_TRUE(parser.has_error()); + EXPECT_FALSE(parser.Parse(patterns[i])); EXPECT_EQ(0U, parser.extensions().size()); } } @@ -158,9 +149,8 @@ WebSocketExtension expected("foo"); expected.Add(WebSocketExtension::Parameter("bar", "baz")); - parser.Parse("foo; bar = \"ba\\z\" "); + EXPECT_TRUE(parser.Parse("foo; bar = \"ba\\z\" ")); - ASSERT_FALSE(parser.has_error()); ASSERT_EQ(1U, parser.extensions().size()); EXPECT_TRUE(expected.Equals(parser.extensions()[0])); }
diff --git a/pdf/paint_manager.cc b/pdf/paint_manager.cc index f452b37..925e1a0 100644 --- a/pdf/paint_manager.cc +++ b/pdf/paint_manager.cc
@@ -97,8 +97,8 @@ } void PaintManager::Invalidate() { - // You must call SetSize before using. - DCHECK(!graphics_.is_null() || has_pending_resize_); + if (graphics_.is_null() && !has_pending_resize_) + return; EnsureCallbackPending(); aggregator_.InvalidateRect(pp::Rect(GetEffectiveSize())); @@ -107,8 +107,8 @@ void PaintManager::InvalidateRect(const pp::Rect& rect) { DCHECK(!in_paint_); - // You must call SetSize before using. - DCHECK(!graphics_.is_null() || has_pending_resize_); + if (graphics_.is_null() && !has_pending_resize_) + return; // Clip the rect to the device area. pp::Rect clipped_rect = rect.Intersect(pp::Rect(GetEffectiveSize())); @@ -123,8 +123,8 @@ const pp::Point& amount) { DCHECK(!in_paint_); - // You must call SetSize before using. - DCHECK(!graphics_.is_null() || has_pending_resize_); + if (graphics_.is_null() && !has_pending_resize_) + return; EnsureCallbackPending();
diff --git a/remoting/remoting_webapp_files.gypi b/remoting/remoting_webapp_files.gypi index 823c55e..15372f8 100644 --- a/remoting/remoting_webapp_files.gypi +++ b/remoting/remoting_webapp_files.gypi
@@ -289,6 +289,7 @@ 'webapp/crd/js/crd_main.js', 'webapp/crd/js/activity.js', 'webapp/crd/js/desktop_remoting.js', + 'webapp/crd/js/desktop_remoting_activity.js', 'webapp/crd/js/it2me_activity.js', 'webapp/crd/js/me2me_activity.js', ],
diff --git a/remoting/webapp/app_remoting/js/app_remoting.js b/remoting/webapp/app_remoting/js/app_remoting.js index ed04bd1..e1749d8 100644 --- a/remoting/webapp/app_remoting/js/app_remoting.js +++ b/remoting/webapp/app_remoting/js/app_remoting.js
@@ -30,10 +30,11 @@ * @constructor * @implements {remoting.ApplicationInterface} * @implements {remoting.ProtocolExtension} + * @implements {remoting.ClientSession.EventHandler} * @extends {remoting.Application} */ remoting.AppRemoting = function(appCapabilities) { - base.inherits(this, remoting.Application, appCapabilities); + base.inherits(this, remoting.Application); /** @private {remoting.ApplicationContextMenu} */ this.contextMenu_ = null; @@ -52,6 +53,11 @@ /** @private */ this.supportsGoogleDrive_ = false; + + /** @private */ + this.sessionConnector_ = remoting.SessionConnector.factory.createConnector( + document.getElementById('client-container'), + appCapabilities, this); }; /** @@ -92,7 +98,7 @@ * @override {remoting.ApplicationInterface} */ remoting.AppRemoting.prototype.signInFailed_ = function(error) { - this.onError_(error); + this.onError(error); }; /** @@ -172,31 +178,13 @@ remoting.Application.Mode.APP_REMOTING, host, new remoting.CredentialsProvider( {fetchThirdPartyToken: fetchThirdPartyToken})); - } else if (response && response.status == 'pending') { - that.onError_(new remoting.Error( + that.onError(new remoting.Error( remoting.Error.Tag.SERVICE_UNAVAILABLE)); } } else { console.error('Invalid "runApplication" response from server.'); - // TODO(garykac) Start using remoting.Error.fromHttpStatus once it has - // been updated to properly report 'unknown' errors (rather than - // reporting them as AUTHENTICATION_FAILED). - if (xhrResponse.status == 0) { - that.onError_(new remoting.Error( - remoting.Error.Tag.NETWORK_FAILURE)); - } else if (xhrResponse.status == 401) { - that.onError_(new remoting.Error( - remoting.Error.Tag.AUTHENTICATION_FAILED)); - } else if (xhrResponse.status == 403) { - that.onError_(new remoting.Error( - remoting.Error.Tag.APP_NOT_AUTHORIZED)); - } else if (xhrResponse.status == 502 || xhrResponse.status == 503) { - that.onError_(new remoting.Error( - remoting.Error.Tag.SERVICE_UNAVAILABLE)); - } else { - that.onError_(remoting.Error.unexpected()); - } + that.onError(remoting.Error.fromHttpStatus(xhrResponse.status)); } }; @@ -217,11 +205,8 @@ /** * @param {remoting.ConnectionInfo} connectionInfo - * @override {remoting.ApplicationInterface} */ -remoting.AppRemoting.prototype.onConnected_ = function(connectionInfo) { - this.initSession_(connectionInfo); - +remoting.AppRemoting.prototype.onConnected = function(connectionInfo) { this.supportsGoogleDrive_ = connectionInfo.session().hasCapability( remoting.ClientSession.Capability.GOOGLE_DRIVE); @@ -237,10 +222,7 @@ } }; -/** - * @override {remoting.ApplicationInterface} - */ -remoting.AppRemoting.prototype.onDisconnected_ = function() { +remoting.AppRemoting.prototype.onDisconnected = function() { base.dispose(this.connectedView_); this.connectedView_ = null; this.stopExtension_(); @@ -249,17 +231,15 @@ /** * @param {!remoting.Error} error - * @override {remoting.ApplicationInterface} */ -remoting.AppRemoting.prototype.onConnectionFailed_ = function(error) { - this.onError_(error); +remoting.AppRemoting.prototype.onConnectionFailed = function(error) { + this.onError(error); }; /** * @param {!remoting.Error} error The error to be localized and displayed. - * @override {remoting.ApplicationInterface} */ -remoting.AppRemoting.prototype.onError_ = function(error) { +remoting.AppRemoting.prototype.onError = function(error) { console.error('Connection failed: ' + error.toString()); remoting.LoadingWindow.close(); remoting.MessageWindow.showErrorMessage(
diff --git a/remoting/webapp/base/js/application.js b/remoting/webapp/base/js/application.js index 4679ab8..4e79fccb 100644 --- a/remoting/webapp/base/js/application.js +++ b/remoting/webapp/base/js/application.js
@@ -13,38 +13,16 @@ var remoting = remoting || {}; /** - * @param {Array<string>} appCapabilities Array of application capabilities. * @constructor - * @implements {remoting.ApplicationInterface} */ -remoting.Application = function(appCapabilities) { +remoting.Application = function() { // Create global factories. remoting.ClientPlugin.factory = new remoting.DefaultClientPluginFactory(); remoting.SessionConnector.factory = new remoting.DefaultSessionConnectorFactory(); - /** @private {Array<string>} */ - this.appCapabilities_ = [ - remoting.ClientSession.Capability.SEND_INITIAL_RESOLUTION, - remoting.ClientSession.Capability.RATE_LIMIT_RESIZE_REQUESTS, - remoting.ClientSession.Capability.VIDEO_RECORDER - ]; - // Append the app-specific capabilities. - this.appCapabilities_.push.apply(this.appCapabilities_, appCapabilities); - - /** @protected {remoting.SessionConnector} */ - this.sessionConnector_ = remoting.SessionConnector.factory.createConnector( - document.getElementById('client-container'), - this.onConnected_.bind(this), - this.onError_.bind(this), - this.onConnectionFailed_.bind(this), - this.appCapabilities_); - /** @protected {remoting.Application.Mode} */ this.connectionMode_ = remoting.Application.Mode.ME2ME; - - /** @private {base.Disposable} */ - this.sessionConnectedHooks_ = null; }; /** @@ -62,13 +40,6 @@ }; /** - * @return {remoting.SessionConnector} The session connector. - */ -remoting.Application.prototype.getSessionConnector = function() { - return this.sessionConnector_; -}; - -/** * Get the connection mode (Me2Me, IT2Me or AppRemoting). * * @return {remoting.Application.Mode} @@ -86,15 +57,6 @@ this.connectionMode_ = mode; }; -/** - * @param {remoting.ClientSession.Capability} capability - * @return {boolean} - */ -remoting.Application.prototype.hasCapability = function(capability) { - var capabilities = this.appCapabilities_; - return capabilities.indexOf(capability) != -1; -}; - /* Disconnect the remoting client. */ remoting.Application.prototype.disconnect = function() { if (remoting.clientSession) { @@ -132,81 +94,18 @@ this.initApplication_(); var that = this; - remoting.identity.getToken(). - then(this.startApplication_.bind(this)). - catch(remoting.Error.handler( - function(/** !remoting.Error */ error) { - if (error.hasTag(remoting.Error.Tag.CANCELLED)) { - that.exitApplication_(); - } else { - that.signInFailed_(error); - } - } - ) - ); + remoting.identity.getToken().then( + this.startApplication_.bind(this) + ).catch(function(/** !remoting.Error */ error) { + if (error.hasTag(remoting.Error.Tag.CANCELLED)) { + that.exitApplication_(); + } else { + that.signInFailed_(error); + } + }); }; /** - * Called when a new session has been connected. - * - * @param {remoting.ConnectionInfo} connectionInfo - * @return {void} Nothing. - * @protected - */ -remoting.Application.prototype.initSession_ = function(connectionInfo) { - this.sessionConnectedHooks_ = new base.Disposables( - new base.EventHook(connectionInfo.session(), 'stateChanged', - this.onSessionFinished_.bind(this)), - new base.RepeatingTimer(this.updateStatistics_.bind(this), 1000) - ); -}; - -/** - * Callback function called when the state of the client plugin changes. The - * current and previous states are available via the |state| member variable. - * - * @param {remoting.ClientSession.StateEvent=} state - * @private - */ -remoting.Application.prototype.onSessionFinished_ = function(state) { - switch (state.current) { - case remoting.ClientSession.State.CLOSED: - console.log('Connection closed by host'); - this.onDisconnected_(); - break; - case remoting.ClientSession.State.FAILED: - var error = remoting.clientSession.getError(); - console.error('Client plugin reported connection failed: ' + - error.toString()); - if (error === null) { - error = remoting.Error.unexpected(); - } - this.onError_(error); - break; - - default: - console.error('Unexpected client plugin state: ' + state.current); - // This should only happen if the web-app and client plugin get out of - // sync, so MISSING_PLUGIN is a suitable error. - this.onError_(new remoting.Error(remoting.Error.Tag.MISSING_PLUGIN)); - break; - } - - base.dispose(this.sessionConnectedHooks_); - this.sessionConnectedHooks_= null; - this.sessionConnector_.closeSession(); -}; - -/** @private */ -remoting.Application.prototype.updateStatistics_ = function() { - var perfstats = remoting.clientSession.getPerfStats(); - remoting.stats.update(perfstats); - remoting.clientSession.logStatistics(perfstats); -}; - - -/* - * remoting.ApplicationInterface * These functions must be overridden in the subclass. */ @@ -242,36 +141,6 @@ }; /** - * @param {remoting.ConnectionInfo} connectionInfo - * @protected - */ -remoting.Application.prototype.onConnected_ = function(connectionInfo) { - base.debug.assert(false, "Subclass must override"); -}; - -/** @protected */ -remoting.Application.prototype.onDisconnected_ = function() { - base.debug.assert(false, "Subclass must override"); -}; - -/** - * @param {!remoting.Error} error - * @protected - */ -remoting.Application.prototype.onConnectionFailed_ = function(error) { - base.debug.assert(false, "Subclass must override"); -}; - -/** - * @param {!remoting.Error} error The error to be localized and displayed. - * @protected - */ -remoting.Application.prototype.onError_ = function(error) { - base.debug.assert(false, "Subclass must override"); -}; - - -/** * The interface specifies the methods that a subclass of remoting.Application * is required implement to override the default behavior. * @@ -316,34 +185,5 @@ */ remoting.ApplicationInterface.prototype.exitApplication_ = function() {}; -/** - * Called when a new session has been connected. - * - * @param {remoting.ConnectionInfo} connectionInfo - */ -remoting.ApplicationInterface.prototype.onConnected_ = - function(connectionInfo) {}; - -/** - * Called when the current session has been disconnected. - */ -remoting.ApplicationInterface.prototype.onDisconnected_ = function() {}; - -/** - * Called when the current session's connection has failed. - * - * @param {!remoting.Error} error - */ -remoting.ApplicationInterface.prototype.onConnectionFailed_ = - function(error) {}; - -/** - * Called when an error needs to be displayed to the user. - * - * @param {!remoting.Error} errorTag The error to be localized and displayed. - */ -remoting.ApplicationInterface.prototype.onError_ = function(errorTag) {}; - - /** @type {remoting.Application} */ remoting.app = null;
diff --git a/remoting/webapp/crd/js/client_plugin_impl.js b/remoting/webapp/crd/js/client_plugin_impl.js index ff8d8ad..c2ba6c0 100644 --- a/remoting/webapp/crd/js/client_plugin_impl.js +++ b/remoting/webapp/crd/js/client_plugin_impl.js
@@ -34,6 +34,9 @@ */ remoting.ClientPluginImpl = function(container, requiredCapabilities) { + // TODO(kelvinp): Hack to remove all plugin elements as our current code does + // not handle connection cancellation properly. + container.innerText = ''; this.plugin_ = remoting.ClientPluginImpl.createPluginElement_(); this.plugin_.id = 'session-client-plugin'; container.appendChild(this.plugin_);
diff --git a/remoting/webapp/crd/js/client_session.js b/remoting/webapp/crd/js/client_session.js index 2e90e97..43a99be 100644 --- a/remoting/webapp/crd/js/client_session.js +++ b/remoting/webapp/crd/js/client_session.js
@@ -71,6 +71,9 @@ this.plugin_ = plugin; plugin.setConnectionEventHandler(this); + /** @private */ + this.connectedDisposables_ = new base.Disposables(); + this.defineEvents(Object.keys(remoting.ClientSession.Events)); }; @@ -309,6 +312,8 @@ * @return {void} Nothing. */ remoting.ClientSession.prototype.dispose = function() { + base.dispose(this.connectedDisposables_); + this.connectedDisposables_ = null; this.plugin_ = null; }; @@ -491,6 +496,15 @@ this.capabilities_ = capabilities; }; +/** @return {boolean} */ +remoting.ClientSession.prototype.isFinished = function() { + var finishedStates = [ + remoting.ClientSession.State.CLOSED, + remoting.ClientSession.State.FAILED, + remoting.ClientSession.State.CONNECTION_DROPPED + ]; + return finishedStates.indexOf(this.getState()) !== -1; +}; /** * @param {remoting.ClientSession.State} newState The new state for the session. * @return {void} Nothing. @@ -498,25 +512,17 @@ */ remoting.ClientSession.prototype.setState_ = function(newState) { var oldState = this.state_; - this.state_ = newState; - var state = this.state_; - if (oldState == remoting.ClientSession.State.CONNECTING || - oldState == remoting.ClientSession.State.AUTHENTICATED) { - if (this.state_ == remoting.ClientSession.State.CLOSED) { - state = remoting.ClientSession.State.CONNECTION_CANCELED; - } else if (this.state_ == remoting.ClientSession.State.FAILED && - this.error_.hasTag(remoting.Error.Tag.HOST_IS_OFFLINE) && - !this.logHostOfflineErrors_) { - // The application requested host-offline errors to be suppressed, for - // example, because this connection attempt is using a cached host JID. - console.log('Suppressing host-offline error.'); - state = remoting.ClientSession.State.CONNECTION_CANCELED; - } - } else if (oldState == remoting.ClientSession.State.CONNECTED && - this.state_ == remoting.ClientSession.State.FAILED) { - state = remoting.ClientSession.State.CONNECTION_DROPPED; + this.state_ = this.translateState_(oldState, newState); + + if (newState == remoting.ClientSession.State.CONNECTED) { + this.connectedDisposables_.add( + new base.RepeatingTimer(this.reportStatistics.bind(this), 1000)); + } else if (this.isFinished()) { + base.dispose(this.connectedDisposables_); + this.connectedDisposables_ = null; } - this.logToServer.logClientSessionStateChange(state, this.error_); + + this.logToServer.logClientSessionStateChange(this.state_, this.error_); this.raiseEvent(remoting.ClientSession.Events.stateChanged, new remoting.ClientSession.StateEvent(newState, oldState) @@ -524,21 +530,33 @@ }; /** - * Returns an associative array with a set of stats for this connection. - * - * @return {remoting.ClientSession.PerfStats} The connection statistics. + * @param {remoting.ClientSession.State} previous + * @param {remoting.ClientSession.State} current + * @return {remoting.ClientSession.State} + * @private */ -remoting.ClientSession.prototype.getPerfStats = function() { - return this.plugin_.getPerfStats(); +remoting.ClientSession.prototype.translateState_ = function(previous, current) { + var State = remoting.ClientSession.State; + if (previous == State.CONNECTING || previous == State.AUTHENTICATED) { + if (current == State.CLOSED) { + return remoting.ClientSession.State.CONNECTION_CANCELED; + } else if (current == State.FAILED && + this.error_.hasTag(remoting.Error.Tag.HOST_IS_OFFLINE) && + !this.logHostOfflineErrors_) { + // The application requested host-offline errors to be suppressed, for + // example, because this connection attempt is using a cached host JID. + console.log('Suppressing host-offline error.'); + return State.CONNECTION_CANCELED; + } + } else if (previous == State.CONNECTED && current == State.FAILED) { + return State.CONNECTION_DROPPED; + } + return current; }; -/** - * Logs statistics. - * - * @param {remoting.ClientSession.PerfStats} stats - */ -remoting.ClientSession.prototype.logStatistics = function(stats) { - this.logToServer.logStatistics(stats); +/** @private */ +remoting.ClientSession.prototype.reportStatistics = function() { + this.logToServer.logStatistics(this.plugin_.getPerfStats()); }; /**
diff --git a/remoting/webapp/crd/js/crd_main.js b/remoting/webapp/crd/js/crd_main.js index d2a4f856..cdfaecf 100644 --- a/remoting/webapp/crd/js/crd_main.js +++ b/remoting/webapp/crd/js/crd_main.js
@@ -133,7 +133,8 @@ }; remoting.hostController.hasFeature( - remoting.HostController.Feature.PAIRING_REGISTRY, onHasFeatureResponse); + remoting.HostController.Feature.PAIRING_REGISTRY). + then(onHasFeatureResponse); remoting.hostController.getLocalHostState(onHostState); }; @@ -177,7 +178,7 @@ remoting.startDesktopRemoting = function() { - remoting.app = new remoting.DesktopRemoting(remoting.app_capabilities()); + remoting.app = new remoting.DesktopRemoting(); remoting.app.start(); };
diff --git a/remoting/webapp/crd/js/desktop_remoting.js b/remoting/webapp/crd/js/desktop_remoting.js index 78ed95fd..29c32a0 100644 --- a/remoting/webapp/crd/js/desktop_remoting.js +++ b/remoting/webapp/crd/js/desktop_remoting.js
@@ -14,27 +14,17 @@ var remoting = remoting || {}; /** - * @param {Array<string>} appCapabilities Array of application capabilities. * @constructor * @implements {remoting.ApplicationInterface} * @extends {remoting.Application} */ -remoting.DesktopRemoting = function(appCapabilities) { - base.inherits(this, remoting.Application, appCapabilities); - - /** @private {remoting.DesktopConnectedView} */ - this.connectedView_ = null; +remoting.DesktopRemoting = function() { + base.inherits(this, remoting.Application); /** @private {remoting.Activity} */ this.activity_ = null; }; -/** @private */ -remoting.DesktopRemoting.prototype.reset_ = function() { - base.dispose(this.connectedView_); - this.connectedView_ = null; -}; - /** * @return {string} Application product name to be used in UI. * @override {remoting.ApplicationInterface} @@ -147,71 +137,6 @@ }; /** - * @param {remoting.ConnectionInfo} connectionInfo - * @override {remoting.ApplicationInterface} - */ -remoting.DesktopRemoting.prototype.onConnected_ = function(connectionInfo) { - this.initSession_(connectionInfo); - - remoting.setMode(remoting.AppMode.IN_SESSION); - if (!base.isAppsV2()) { - remoting.toolbar.center(); - remoting.toolbar.preview(); - } - - this.connectedView_ = new remoting.DesktopConnectedView( - document.getElementById('client-container'), connectionInfo); - - // By default, under ChromeOS, remap the right Control key to the right - // Win / Cmd key. - if (remoting.platformIsChromeOS()) { - connectionInfo.plugin().setRemapKeys('0x0700e4>0x0700e7'); - } - - if (connectionInfo.session().hasCapability( - remoting.ClientSession.Capability.VIDEO_RECORDER)) { - var recorder = new remoting.VideoFrameRecorder(); - connectionInfo.plugin().extensions().register(recorder); - this.connectedView_.setVideoFrameRecorder(recorder); - } - - this.activity_.onConnected(connectionInfo); -}; - -/** - * @override {remoting.ApplicationInterface} - */ -remoting.DesktopRemoting.prototype.onDisconnected_ = function() { - this.activity_.onDisconnected(); - this.reset_(); -}; - -/** - * @param {!remoting.Error} error - * @override {remoting.ApplicationInterface} - */ -remoting.DesktopRemoting.prototype.onConnectionFailed_ = function(error) { - this.activity_.onConnectionFailed(error); -}; - -/** - * @param {!remoting.Error} error The error to be localized and displayed. - * @override {remoting.ApplicationInterface} - */ -remoting.DesktopRemoting.prototype.onError_ = function(error) { - console.error('Connection failed: ' + error.toString()); - - if (error.hasTag(remoting.Error.Tag.AUTHENTICATION_FAILED)) { - remoting.setMode(remoting.AppMode.HOME); - remoting.handleAuthFailureAndRelaunch(); - return; - } - - this.activity_.onError(error); - this.reset_(); -}; - -/** * Determine whether or not the app is running in a window. * @param {function(boolean):void} callback Callback to receive whether or not * the current tab is running in windowed mode. @@ -260,7 +185,8 @@ /** @returns {remoting.DesktopConnectedView} */ remoting.DesktopRemoting.prototype.getConnectedViewForTesting = function() { - return this.connectedView_; + var activity = /** @type {remoting.Me2MeActivity} */ (this.activity_); + return activity.getDesktopActivity().getConnectedView(); }; /** @@ -272,14 +198,8 @@ */ remoting.DesktopRemoting.prototype.connectMe2Me_ = function(hostId) { var host = remoting.hostList.getHostForId(hostId); - // The Me2MeActivity triggers a reconnect underneath the hood on connection - // failure, but it won't notify the DesktopRemoting upon successful - // re-connection. Therefore, we can't dispose the activity on connection - // failure. Instead, the activity is only disposed when a new one is - // created. This would be fixed once |sessionConnector| is moved out of the - // application. base.dispose(this.activity_); - this.activity_ = new remoting.Me2MeActivity(this.sessionConnector_, host); + this.activity_ = new remoting.Me2MeActivity(host); this.activity_.start(); }; @@ -290,6 +210,6 @@ */ remoting.DesktopRemoting.prototype.connectIt2Me_ = function() { base.dispose(this.activity_); - this.activity_ = new remoting.It2MeActivity(this.sessionConnector_); + this.activity_ = new remoting.It2MeActivity(); this.activity_.start(); };
diff --git a/remoting/webapp/crd/js/desktop_remoting_activity.js b/remoting/webapp/crd/js/desktop_remoting_activity.js new file mode 100644 index 0000000..768eccc --- /dev/null +++ b/remoting/webapp/crd/js/desktop_remoting_activity.js
@@ -0,0 +1,101 @@ +// 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. + +/** @suppress {duplicate} */ +var remoting = remoting || {}; + +(function() { + +'use strict'; + +/** + * This class provides common functionality to Me2MeActivity and It2MeActivity, + * e.g. constructing the relevant UX, and delegate the custom handling of the + * session state changes to the |parentActivity|. + * + * @param {remoting.Activity} parentActivity + * @implements {remoting.ClientSession.EventHandler} + * @implements {base.Disposable} + * @constructor + */ +remoting.DesktopRemotingActivity = function(parentActivity) { + /** @private */ + this.parentActivity_ = parentActivity; + /** @private {remoting.DesktopConnectedView} */ + this.connectedView_ = null; +}; + +/** + * @param {remoting.ConnectionInfo} connectionInfo + */ +remoting.DesktopRemotingActivity.prototype.onConnected = + function(connectionInfo) { + remoting.setMode(remoting.AppMode.IN_SESSION); + if (!base.isAppsV2()) { + remoting.toolbar.center(); + remoting.toolbar.preview(); + } + + this.connectedView_ = new remoting.DesktopConnectedView( + document.getElementById('client-container'), connectionInfo); + + // By default, under ChromeOS, remap the right Control key to the right + // Win / Cmd key. + if (remoting.platformIsChromeOS()) { + connectionInfo.plugin().setRemapKeys('0x0700e4>0x0700e7'); + } + + if (connectionInfo.session().hasCapability( + remoting.ClientSession.Capability.VIDEO_RECORDER)) { + var recorder = new remoting.VideoFrameRecorder(); + connectionInfo.plugin().extensions().register(recorder); + this.connectedView_.setVideoFrameRecorder(recorder); + } + + this.parentActivity_.onConnected(connectionInfo); +}; + +remoting.DesktopRemotingActivity.prototype.onDisconnected = function() { + this.parentActivity_.onDisconnected(); + base.dispose(this.connectedView_); + this.connectedView_ = null; +}; + +/** + * @param {!remoting.Error} error + */ +remoting.DesktopRemotingActivity.prototype.onConnectionFailed = + function(error) { + this.parentActivity_.onConnectionFailed(error); +}; + +/** + * @param {!remoting.Error} error The error to be localized and displayed. + */ +remoting.DesktopRemotingActivity.prototype.onError = function(error) { + console.error('Connection failed: ' + error.toString()); + + if (error.hasTag(remoting.Error.Tag.AUTHENTICATION_FAILED)) { + remoting.setMode(remoting.AppMode.HOME); + remoting.handleAuthFailureAndRelaunch(); + return; + } + + this.parentActivity_.onError(error); + + base.dispose(this.connectedView_); + this.connectedView_ = null; +}; + +remoting.DesktopRemotingActivity.prototype.dispose = function() { + base.dispose(this.connectedView_); + this.connectedView_ = null; +}; + +/** @return {remoting.DesktopConnectedView} */ +remoting.DesktopRemotingActivity.prototype.getConnectedView = function() { + return this.connectedView_; +}; + +})();
diff --git a/remoting/webapp/crd/js/host_controller.js b/remoting/webapp/crd/js/host_controller.js index 0a88296..cde869a 100644 --- a/remoting/webapp/crd/js/host_controller.js +++ b/remoting/webapp/crd/js/host_controller.js
@@ -72,7 +72,7 @@ } }; - hostDaemonFacade.getDaemonVersion(printVersion, function() { + hostDaemonFacade.getDaemonVersion().then(printVersion, function() { console.log('Host version not available.'); }); @@ -90,24 +90,54 @@ }; /** - * @param {remoting.HostController.Feature} feature The feature to test for. - * @param {function(boolean):void} callback - * @return {void} + * Information relating to user consent to collect usage stats. The + * fields are: + * + * supported: True if crash dump reporting is supported by the host. + * + * allowed: True if crash dump reporting is allowed. + * + * setByPolicy: True if crash dump reporting is controlled by policy. + * + * @typedef {{ + * supported:boolean, + * allowed:boolean, + * setByPolicy:boolean + * }} */ -remoting.HostController.prototype.hasFeature = function(feature, callback) { +remoting.UsageStatsConsent; + +/** + * @typedef {{ + * userEmail:string, + * refreshToken:string + * }} + */ +remoting.XmppCredentials; + +/** + * @typedef {{ + * privateKey:string, + * publicKey:string + * }} + */ +remoting.KeyPair; + +/** + * @param {remoting.HostController.Feature} feature The feature to test for. + * @return {!Promise<boolean>} A promise that always resolves. + */ +remoting.HostController.prototype.hasFeature = function(feature) { // TODO(rmsousa): This could synchronously return a boolean, provided it were // only called after native messaging is completely initialized. - this.hostDaemonFacade_.hasFeature(feature, callback); + return this.hostDaemonFacade_.hasFeature(feature); }; /** - * @param {function(boolean, boolean, boolean):void} onDone Callback to be - * called when done. - * @param {function(!remoting.Error):void} onError Callback to be called on - * error. + * @return {!Promise<remoting.UsageStatsConsent>} */ -remoting.HostController.prototype.getConsent = function(onDone, onError) { - this.hostDaemonFacade_.getUsageStatsConsent(onDone, onError); +remoting.HostController.prototype.getConsent = function() { + return this.hostDaemonFacade_.getUsageStatsConsent(); }; /** @@ -115,159 +145,48 @@ * * @param {string} hostPin Host PIN. * @param {boolean} consent The user's consent to crash dump reporting. - * @param {function():void} onDone Callback to be called when done. - * @param {function(!remoting.Error):void} onError Callback to be called on - * error. - * @return {void} Nothing. + * @return {!Promise<void>} A promise resolved once the host is started. */ -remoting.HostController.prototype.start = function(hostPin, consent, onDone, - onError) { +remoting.HostController.prototype.start = function(hostPin, consent) { /** @type {remoting.HostController} */ var that = this; + // Start a bunch of requests with no side-effects. + var hostNamePromise = this.hostDaemonFacade_.getHostName(); + var hasOauthPromise = + this.hasFeature(remoting.HostController.Feature.OAUTH_CLIENT); + var keyPairPromise = this.hostDaemonFacade_.generateKeyPair(); + var oauthTokenPromise = remoting.identity.getToken(); + var hostClientIdPromise = hasOauthPromise.then(function(hasOauth) { + if (hasOauth) { + return that.hostDaemonFacade_.getHostClientId(); + } else { + return null; + } + }); var newHostId = base.generateUuid(); + var pinHashPromise = this.hostDaemonFacade_.getPinHash(newHostId, hostPin); - /** @param {!remoting.Error} error */ - function onStartError(error) { - // Unregister the host if we failed to start it. - remoting.hostList.unregisterHostById(newHostId); - onError(error); - } + // Try to register the host. + /** @type {!Promise<!remoting.Xhr.Response>} */ + var registrationResultPromise = Promise.all([ + hostClientIdPromise, + hostNamePromise, + oauthTokenPromise, + keyPairPromise + ]).then(function(/** Array */ a) { + var hostClientId = /** @type {string} */ (a[0]); + var hostName = /** @type {string} */ (a[1]); + var oauthToken = /** @type {string} */ (a[2]); + var keyPair = /** @type {remoting.KeyPair} */ (a[3]); - /** - * @param {string} hostName - * @param {string} publicKey - * @param {remoting.HostController.AsyncResult} result - */ - function onStarted(hostName, publicKey, result) { - if (result == remoting.HostController.AsyncResult.OK) { - remoting.hostList.onLocalHostStarted(hostName, newHostId, publicKey); - onDone(); - } else if (result == remoting.HostController.AsyncResult.CANCELLED) { - onStartError(new remoting.Error(remoting.Error.Tag.CANCELLED)); - } else { - onStartError(remoting.Error.unexpected()); - } - } - - /** - * @param {string} hostName - * @param {string} publicKey - * @param {string} privateKey - * @param {?string} xmppLogin - * @param {?string} refreshToken - * @param {?string} clientBaseJid - * @param {string} hostSecretHash - */ - function startHostWithHash(hostName, publicKey, privateKey, xmppLogin, - refreshToken, clientBaseJid, hostSecretHash) { - var hostConfig = { - xmpp_login: xmppLogin, - oauth_refresh_token: refreshToken, - host_id: newHostId, - host_name: hostName, - host_secret_hash: hostSecretHash, - private_key: privateKey - }; - var hostOwner = clientBaseJid; - remoting.identity.getEmail().then( - function(/** string */ hostOwnerEmail) { - if (hostOwner != xmppLogin) { - hostConfig['host_owner'] = hostOwner; - if (hostOwnerEmail != hostOwner) { - hostConfig['host_owner_email'] = hostOwnerEmail; - } - } - that.hostDaemonFacade_.startDaemon( - hostConfig, consent, onStarted.bind(null, hostName, publicKey), - onStartError); - }); - } - - /** - * @param {string} hostName - * @param {string} publicKey - * @param {string} privateKey - * @param {string} email - * @param {string} refreshToken - * @param {string} clientBaseJid - */ - function onClientBaseJid( - hostName, publicKey, privateKey, email, refreshToken, clientBaseJid) { - that.hostDaemonFacade_.getPinHash( - newHostId, hostPin, - startHostWithHash.bind(null, hostName, publicKey, privateKey, - email, refreshToken, clientBaseJid), - onError); - } - - /** - * @param {string} hostName - * @param {string} publicKey - * @param {string} privateKey - * @param {string} email - * @param {string} refreshToken - */ - function onServiceAccountCredentials( - hostName, publicKey, privateKey, email, refreshToken) { - that.getClientBaseJid_( - onClientBaseJid.bind( - null, hostName, publicKey, privateKey, email, refreshToken), - onStartError); - } - - /** - * @param {string} hostName - * @param {string} publicKey - * @param {string} privateKey - * @param {!remoting.Xhr.Response} response - */ - function onRegistered( - hostName, publicKey, privateKey, response) { - var success = (response.status == 200); - - if (success) { - var result = base.jsonParseSafe(response.getText()); - if ('data' in result && 'authorizationCode' in result['data']) { - that.hostDaemonFacade_.getCredentialsFromAuthCode( - result['data']['authorizationCode'], - onServiceAccountCredentials.bind( - null, hostName, publicKey, privateKey), - onError); - } else { - // No authorization code returned, use regular user credential flow. - remoting.identity.getEmail().then( - function(/** string */ email) { - that.hostDaemonFacade_.getPinHash( - newHostId, hostPin, startHostWithHash.bind( - null, hostName, publicKey, privateKey, - email, remoting.oauth2.getRefreshToken(), email), - onError); - }); - } - } else { - console.log('Failed to register the host. Status: ' + response.status + - ' response: ' + response.getText()); - onError(new remoting.Error(remoting.Error.Tag.REGISTRATION_FAILED)); - } - } - - /** - * @param {string} hostName - * @param {string} privateKey - * @param {string} publicKey - * @param {?string} hostClientId - * @param {string} oauthToken - */ - function doRegisterHost( - hostName, privateKey, publicKey, hostClientId, oauthToken) { var newHostDetails = { data: { - hostId: newHostId, - hostName: hostName, - publicKey: publicKey + hostId: newHostId, + hostName: hostName, + publicKey: keyPair.publicKey } }; - new remoting.Xhr({ + return new remoting.Xhr({ method: 'POST', url: remoting.settings.DIRECTORY_API_BASE_URL + '/@me/hosts', urlParams: { @@ -275,63 +194,131 @@ }, jsonContent: newHostDetails, oauthToken: oauthToken - }).start().then(onRegistered.bind(null, hostName, publicKey, privateKey)); - } + }).start(); + }); - /** - * @param {string} hostName - * @param {string} privateKey - * @param {string} publicKey - * @param {string} hostClientId - */ - function onHostClientId( - hostName, privateKey, publicKey, hostClientId) { - remoting.identity.getToken().then( - doRegisterHost.bind( - null, hostName, privateKey, publicKey, hostClientId), - remoting.Error.handler(onError)); - } + /** @type {boolean} */ + var hostRegistered = false; - /** - * @param {string} hostName - * @param {string} privateKey - * @param {string} publicKey - * @param {boolean} hasFeature - */ - function onHasFeatureOAuthClient( - hostName, privateKey, publicKey, hasFeature) { - if (hasFeature) { - that.hostDaemonFacade_.getHostClientId( - onHostClientId.bind(null, hostName, privateKey, publicKey), onError); + // Extract an optional auth code from the host response. The + // absence of an auth code is represented by an empty string. + /** @type {!Promise<string>} */ + var authCodePromise = registrationResultPromise.then(function(response) { + if (response.status == 200) { + hostRegistered = true; + var result = base.jsonParseSafe(response.getText()); + if (result['data']) { + return base.getStringAttr(result['data'], 'authorizationCode', ''); + } else { + return ''; + } } else { - remoting.identity.getToken().then( - doRegisterHost.bind( - null, hostName, privateKey, publicKey, null), - remoting.Error.handler(onError)); + console.log( + 'Failed to register the host. Status: ' + response.status + + ' response: ' + response.getText()); + throw new remoting.Error(remoting.Error.Tag.REGISTRATION_FAILED); } - } + }); - /** - * @param {string} hostName - * @param {string} privateKey - * @param {string} publicKey - */ - function onKeyGenerated(hostName, privateKey, publicKey) { - that.hasFeature( - remoting.HostController.Feature.OAUTH_CLIENT, - onHasFeatureOAuthClient.bind(null, hostName, privateKey, publicKey)); - } + // Get XMPP creditials. + var xmppCredsPromise = authCodePromise.then(function(authCode) { + if (authCode) { + // Use auth code supplied by registry. + return that.hostDaemonFacade_.getCredentialsFromAuthCode(authCode); + } else { + // No authorization code returned, use regular Chrome + // identitial credential flow. + return remoting.identity.getEmail().then(function(/** string */ email) { + return { + userEmail: email, + refreshToken: remoting.oauth2.getRefreshToken() + }; + }); + } + }); - /** - * @param {string} hostName - * @return {void} Nothing. - */ - function startWithHostname(hostName) { - that.hostDaemonFacade_.generateKeyPair(onKeyGenerated.bind(null, hostName), - onError); - } + // Get as JID to use as the host owner. + var hostOwnerPromise = authCodePromise.then(function(authCode) { + if (authCode) { + return that.getClientBaseJid_(); + } else { + return remoting.identity.getEmail(); + } + }); - this.hostDaemonFacade_.getHostName(startWithHostname, onError); + // Build an initial host configuration. + /** @type {!Promise<!Object>} */ + var hostConfigNoOwnerPromise = Promise.all([ + hostNamePromise, + pinHashPromise, + xmppCredsPromise, + keyPairPromise + ]).then(function(/** Array */ a) { + var hostName = /** @type {string} */ (a[0]); + var hostSecretHash = /** @type {string} */ (a[1]); + var xmppCreds = /** @type {remoting.XmppCredentials} */ (a[2]); + var keyPair = /** @type {remoting.KeyPair} */ (a[3]); + return { + xmpp_login: xmppCreds.userEmail, + oauth_refresh_token: xmppCreds.refreshToken, + host_id: newHostId, + host_name: hostName, + host_secret_hash: hostSecretHash, + private_key: keyPair.privateKey + }; + }); + + // Add host_owner and host_owner_email fields to the host config if + // necessary. This promise resolves to the same value as + // hostConfigNoOwnerPromise, with not until the extra fields are + // either added or determined to be redundant. + /** @type {!Promise<!Object>} */ + var hostConfigWithOwnerPromise = Promise.all([ + hostConfigNoOwnerPromise, + hostOwnerPromise, + remoting.identity.getEmail(), + xmppCredsPromise + ]).then(function(/** Array */ a) { + var hostConfig = /** @type {!Object} */ (a[0]); + var hostOwner = /** @type {string} */ (a[1]); + var hostOwnerEmail = /** @type {string} */ (a[2]); + var xmppCreds = /** @type {remoting.XmppCredentials} */ (a[3]); + if (hostOwner != xmppCreds.userEmail) { + hostConfig['host_owner'] = hostOwner; + if (hostOwnerEmail != hostOwner) { + hostConfig['host_owner_email'] = hostOwnerEmail; + } + } + return hostConfig; + }); + + // Start the daemon. + /** @type {!Promise<remoting.HostController.AsyncResult>} */ + var startDaemonResultPromise = + hostConfigWithOwnerPromise.then(function(hostConfig) { + return that.hostDaemonFacade_.startDaemon(hostConfig, consent); + }); + + // Update the UI or report an error. + return startDaemonResultPromise.then(function(result) { + if (result == remoting.HostController.AsyncResult.OK) { + return hostNamePromise.then(function(hostName) { + return keyPairPromise.then(function(keyPair) { + remoting.hostList.onLocalHostStarted( + hostName, newHostId, keyPair.publicKey); + }); + }); + } else if (result == remoting.HostController.AsyncResult.CANCELLED) { + throw new remoting.Error(remoting.Error.Tag.CANCELLED); + } else { + throw remoting.Error.unexpected(); + } + }).catch(function(error) { + if (hostRegistered) { + remoting.hostList.unregisterHostById(newHostId); + } + throw error; + }); }; /** @@ -365,7 +352,8 @@ } } - this.hostDaemonFacade_.stopDaemon(onStopped, onError); + this.hostDaemonFacade_.stopDaemon().then( + onStopped, remoting.Error.handler(onError)); }; /** @@ -407,8 +395,8 @@ var newConfig = { host_secret_hash: pinHash }; - that.hostDaemonFacade_.updateDaemonConfig(newConfig, onConfigUpdated, - onError); + that.hostDaemonFacade_.updateDaemonConfig(newConfig).then( + onConfigUpdated, remoting.Error.handler(onError)); } /** @param {Object} config */ @@ -419,13 +407,14 @@ } /** @type {string} */ var hostId = config['host_id']; - that.hostDaemonFacade_.getPinHash( - hostId, newPin, updateDaemonConfigWithHash, onError); + that.hostDaemonFacade_.getPinHash(hostId, newPin).then( + updateDaemonConfigWithHash, remoting.Error.handler(onError)); } // TODO(sergeyu): When crbug.com/121518 is fixed: replace this call // with an unprivileged version if that is necessary. - this.hostDaemonFacade_.getDaemonConfig(onConfig, onError); + this.hostDaemonFacade_.getDaemonConfig().then( + onConfig, remoting.Error.handler(onError)); }; /** @@ -441,7 +430,8 @@ remoting.HostController.State.NOT_INSTALLED : remoting.HostController.State.UNKNOWN); } - this.hostDaemonFacade_.getDaemonState(onDone, onError); + this.hostDaemonFacade_.getDaemonState().then( + onDone, remoting.Error.handler(onError)); }; /** @@ -461,7 +451,7 @@ onDone(hostId); }; - this.hostDaemonFacade_.getDaemonConfig(onConfig, function(error) { + this.hostDaemonFacade_.getDaemonConfig().then(onConfig, function(error) { onDone(null); }); }; @@ -475,7 +465,8 @@ */ remoting.HostController.prototype.getPairedClients = function(onDone, onError) { - this.hostDaemonFacade_.getPairedClients(onDone, onError); + this.hostDaemonFacade_.getPairedClients().then( + onDone, remoting.Error.handler(onError)); }; /** @@ -488,7 +479,8 @@ */ remoting.HostController.prototype.deletePairedClient = function( client, onDone, onError) { - this.hostDaemonFacade_.deletePairedClient(client, onDone, onError); + this.hostDaemonFacade_.deletePairedClient(client).then( + onDone, remoting.Error.handler(onError)); }; /** @@ -500,7 +492,8 @@ */ remoting.HostController.prototype.clearPairedClients = function( onDone, onError) { - this.hostDaemonFacade_.clearPairedClients(onDone, onError); + this.hostDaemonFacade_.clearPairedClients().then( + onDone, remoting.Error.handler(onError)); }; /** @@ -509,53 +502,45 @@ * non-Gmail accounts, it may be different. * * @private - * @param {function(string): void} onSuccess - * @param {function(!remoting.Error): void} onError + * @return {!Promise<string>} */ -remoting.HostController.prototype.getClientBaseJid_ = function( - onSuccess, onError) { +remoting.HostController.prototype.getClientBaseJid_ = function() { /** @type {remoting.SignalStrategy} */ var signalStrategy = null; - /** @param {remoting.SignalStrategy.State} state */ - var onState = function(state) { - switch (state) { - case remoting.SignalStrategy.State.CONNECTED: + var result = new Promise(function(resolve, reject) { + /** @param {remoting.SignalStrategy.State} state */ + var onState = function(state) { + switch (state) { + case remoting.SignalStrategy.State.CONNECTED: var jid = signalStrategy.getJid().split('/')[0].toLowerCase(); base.dispose(signalStrategy); signalStrategy = null; - onSuccess(jid); + resolve(jid); break; - case remoting.SignalStrategy.State.FAILED: + case remoting.SignalStrategy.State.FAILED: var error = signalStrategy.getError(); base.dispose(signalStrategy); signalStrategy = null; - onError(error); + reject(error); break; - } - }; + } + }; - signalStrategy = remoting.SignalStrategy.create(); - signalStrategy.setStateChangedCallback(onState); + signalStrategy = remoting.SignalStrategy.create(); + signalStrategy.setStateChangedCallback(onState); + }); - /** @param {string} token */ - function connectSignalingWithToken(token) { - remoting.identity.getEmail().then( - connectSignalingWithTokenAndEmail.bind(null, token), - remoting.Error.handler(onError)); - } + var tokenPromise = remoting.identity.getToken(); + var emailPromise = remoting.identity.getEmail(); + tokenPromise.then(function(/** string */ token) { + emailPromise.then(function(/** string */ email) { + signalStrategy.connect(remoting.settings.XMPP_SERVER, email, token); + }); + }); - /** - * @param {string} token - * @param {string} email - */ - function connectSignalingWithTokenAndEmail(token, email) { - signalStrategy.connect(remoting.settings.XMPP_SERVER, email, token); - } - - remoting.identity.getToken().then( - connectSignalingWithToken, remoting.Error.handler(onError)); + return result; }; /** @type {remoting.HostController} */
diff --git a/remoting/webapp/crd/js/host_controller_unittest.js b/remoting/webapp/crd/js/host_controller_unittest.js index baf5390..f65dc97 100644 --- a/remoting/webapp/crd/js/host_controller_unittest.js +++ b/remoting/webapp/crd/js/host_controller_unittest.js
@@ -51,7 +51,6 @@ var FAKE_HOST_CLIENT_ID = '<FAKE_HOST_CLIENT_ID>'; var FAKE_CLIENT_JID = '<FAKE_CLIENT_JID>'; var FAKE_CLIENT_BASE_JID = '<FAKE_CLIENT_BASE_JID>'; -var FAKE_XMPP_LOGIN = '<FAKE_XMPP_LOGIN>'; var FAKE_IDENTITY_TOKEN = '<FAKE_IDENTITY_TOKEN>'; /** @type {sinon.Spy|Function} */ @@ -225,43 +224,18 @@ }); } -// Check that hasFeature returns false for missing features. -QUnit.test('hasFeature returns false', function(assert) { - return new Promise(function(resolve, reject) { - controller.hasFeature( - remoting.HostController.Feature.PAIRING_REGISTRY, - resolve); - }).then(function(/** boolean */ result) { - assert.equal(result, false); - }); -}); - -// Check that hasFeature returns true for supported features. -QUnit.test('hasFeature returns true', function(assert) { - return new Promise(function(resolve, reject) { - controller.hasFeature( - remoting.HostController.Feature.OAUTH_CLIENT, - resolve); - }).then(function(/** boolean */ result) { - assert.equal(result, true); - }); -}); - // Check what happens when the HostDaemonFacade's getHostName method // fails. QUnit.test('start with getHostName failure', function(assert) { mockHostDaemonFacade.hostName = null; - return new Promise(function(resolve, reject) { - controller.start(FAKE_HOST_PIN, true, function() { - reject('test failed'); - }, function(/** remoting.Error */ e) { - assert.equal(e.getDetail(), 'getHostName'); - assert.equal(e.getTag(), remoting.Error.Tag.UNEXPECTED); - assert.equal(unregisterHostByIdSpy.callCount, 0); - assert.equal(onLocalHostStartedSpy.callCount, 0); - assert.equal(startDaemonSpy.callCount, 0); - resolve(null); - }); + return controller.start(FAKE_HOST_PIN, true).then(function() { + throw 'test failed'; + }, function(/** remoting.Error */ e) { + assert.equal(e.getDetail(), 'getHostName'); + assert.equal(e.getTag(), remoting.Error.Tag.UNEXPECTED); + assert.equal(unregisterHostByIdSpy.callCount, 0); + assert.equal(onLocalHostStartedSpy.callCount, 0); + assert.equal(startDaemonSpy.callCount, 0); }); }); @@ -270,17 +244,14 @@ QUnit.test('start with generateKeyPair failure', function(assert) { mockHostDaemonFacade.publicKey = null; mockHostDaemonFacade.privateKey = null; - return new Promise(function(resolve, reject) { - controller.start(FAKE_HOST_PIN, true, function() { - reject('test failed'); - }, function(/** remoting.Error */ e) { - assert.equal(e.getDetail(), 'generateKeyPair'); - assert.equal(e.getTag(), remoting.Error.Tag.UNEXPECTED); - assert.equal(unregisterHostByIdSpy.callCount, 0); - assert.equal(onLocalHostStartedSpy.callCount, 0); - assert.equal(startDaemonSpy.callCount, 0); - resolve(null); - }); + return controller.start(FAKE_HOST_PIN, true).then(function() { + throw 'test failed'; + }, function(/** remoting.Error */ e) { + assert.equal(e.getDetail(), 'generateKeyPair'); + assert.equal(e.getTag(), remoting.Error.Tag.UNEXPECTED); + assert.equal(unregisterHostByIdSpy.callCount, 0); + assert.equal(onLocalHostStartedSpy.callCount, 0); + assert.equal(startDaemonSpy.callCount, 0); }); }); @@ -288,17 +259,14 @@ // method fails. QUnit.test('start with getHostClientId failure', function(assert) { mockHostDaemonFacade.hostClientId = null; - return new Promise(function(resolve, reject) { - controller.start(FAKE_HOST_PIN, true, function() { - reject('test failed'); - }, function(/** remoting.Error */ e) { - assert.equal(e.getDetail(), 'getHostClientId'); - assert.equal(e.getTag(), remoting.Error.Tag.UNEXPECTED); - assert.equal(unregisterHostByIdSpy.callCount, 0); - assert.equal(onLocalHostStartedSpy.callCount, 0); - assert.equal(startDaemonSpy.callCount, 0); - resolve(null); - }); + return controller.start(FAKE_HOST_PIN, true).then(function() { + throw 'test failed'; + }, function(/** remoting.Error */ e) { + assert.equal(e.getDetail(), 'getHostClientId'); + assert.equal(e.getTag(), remoting.Error.Tag.UNEXPECTED); + assert.equal(unregisterHostByIdSpy.callCount, 0); + assert.equal(onLocalHostStartedSpy.callCount, 0); + assert.equal(startDaemonSpy.callCount, 0); }); }); @@ -307,16 +275,13 @@ QUnit.test('start with host registration failure', function(assert) { remoting.MockXhr.setEmptyResponseFor( 'POST', 'DIRECTORY_API_BASE_URL/@me/hosts', 500); - return new Promise(function(resolve, reject) { - controller.start(FAKE_HOST_PIN, true, function() { - reject('test failed'); - }, function(/** remoting.Error */ e) { - assert.equal(e.getTag(), remoting.Error.Tag.REGISTRATION_FAILED); - assert.equal(unregisterHostByIdSpy.callCount, 0); - assert.equal(onLocalHostStartedSpy.callCount, 0); - assert.equal(startDaemonSpy.callCount, 0); - resolve(null); - }); + return controller.start(FAKE_HOST_PIN, true).then(function() { + throw 'test failed'; + }, function(/** remoting.Error */ e) { + assert.equal(e.getTag(), remoting.Error.Tag.REGISTRATION_FAILED); + assert.equal(unregisterHostByIdSpy.callCount, 0); + assert.equal(onLocalHostStartedSpy.callCount, 0); + assert.equal(startDaemonSpy.callCount, 0); }); }); @@ -326,18 +291,14 @@ mockHostDaemonFacade.useEmail = null; mockHostDaemonFacade.refreshToken = null; queueRegistryResponse(assert, true); - return new Promise(function(resolve, reject) { - controller.start(FAKE_HOST_PIN, true, function() { - reject('test failed'); - }, function(/** remoting.Error */ e) { - assert.equal(e.getDetail(), 'getCredentialsFromAuthCode'); - assert.equal(e.getTag(), remoting.Error.Tag.UNEXPECTED); - assert.equal(getCredentialsFromAuthCodeSpy.callCount, 1); - assert.equal(unregisterHostByIdSpy.callCount, 0); - assert.equal(onLocalHostStartedSpy.callCount, 0); - assert.equal(startDaemonSpy.callCount, 0); - resolve(null); - }); + return controller.start(FAKE_HOST_PIN, true).then(function() { + throw 'test failed'; + }, function(/** remoting.Error */ e) { + assert.equal(e.getDetail(), 'getCredentialsFromAuthCode'); + assert.equal(e.getTag(), remoting.Error.Tag.UNEXPECTED); + assert.equal(getCredentialsFromAuthCodeSpy.callCount, 1); + assert.equal(onLocalHostStartedSpy.callCount, 0); + assert.equal(startDaemonSpy.callCount, 0); }); }); @@ -347,17 +308,13 @@ QUnit.test('start with getRefreshToken+getPinHash failure', function(assert) { mockHostDaemonFacade.pinHashFunc = null; queueRegistryResponse(assert, false); - return new Promise(function(resolve, reject) { - controller.start(FAKE_HOST_PIN, true, function() { - reject('test failed'); - }, function(/** remoting.Error */ e) { - assert.equal(e.getDetail(), 'getPinHash'); - assert.equal(e.getTag(), remoting.Error.Tag.UNEXPECTED); - assert.equal(unregisterHostByIdSpy.callCount, 0); - assert.equal(onLocalHostStartedSpy.callCount, 0); - assert.equal(startDaemonSpy.callCount, 0); - resolve(null); - }); + return controller.start(FAKE_HOST_PIN, true).then(function() { + throw 'test failed'; + }, function(/** remoting.Error */ e) { + assert.equal(e.getDetail(), 'getPinHash'); + assert.equal(e.getTag(), remoting.Error.Tag.UNEXPECTED); + assert.equal(onLocalHostStartedSpy.callCount, 0); + assert.equal(startDaemonSpy.callCount, 0); }); }); @@ -365,15 +322,12 @@ QUnit.test('start with signalStrategy failure', function(assert) { queueRegistryResponse(assert, true); stubSignalStrategyConnect(false); - return new Promise(function(resolve, reject) { - controller.start(FAKE_HOST_PIN, true, function() { - reject('test failed'); - }, function(/** remoting.Error */ e) { - assert.equal(e.getDetail(), 'setStateForTesting'); - assert.equal(e.getTag(), remoting.Error.Tag.UNEXPECTED); - assert.equal(unregisterHostByIdSpy.callCount, 1); - resolve(null); - }); + return controller.start(FAKE_HOST_PIN, true).then(function() { + throw 'test failed'; + }, function(/** remoting.Error */ e) { + assert.equal(e.getDetail(), 'setStateForTesting'); + assert.equal(e.getTag(), remoting.Error.Tag.UNEXPECTED); + assert.equal(unregisterHostByIdSpy.callCount, 1); }); }); @@ -384,17 +338,14 @@ queueRegistryResponse(assert, true); stubSignalStrategyConnect(true); mockHostDaemonFacade.startDaemonResult = null; - return new Promise(function(resolve, reject) { - controller.start(FAKE_HOST_PIN, true, function() { - reject('test failed'); - }, function(/** remoting.Error */ e) { - assert.equal(e.getDetail(), 'startDaemon'); - assert.equal(e.getTag(), remoting.Error.Tag.UNEXPECTED); - assert.equal(unregisterHostByIdSpy.callCount, 1); - assert.equal(unregisterHostByIdSpy.args[0][0], FAKE_HOST_ID); - assert.equal(onLocalHostStartedSpy.callCount, 0); - resolve(null); - }); + return controller.start(FAKE_HOST_PIN, true).then(function() { + throw 'test failed'; + }, function(/** remoting.Error */ e) { + assert.equal(e.getDetail(), 'startDaemon'); + assert.equal(e.getTag(), remoting.Error.Tag.UNEXPECTED); + assert.equal(unregisterHostByIdSpy.callCount, 1); + assert.equal(unregisterHostByIdSpy.args[0][0], FAKE_HOST_ID); + assert.equal(onLocalHostStartedSpy.callCount, 0); }); }); @@ -405,16 +356,13 @@ stubSignalStrategyConnect(true); mockHostDaemonFacade.startDaemonResult = remoting.HostController.AsyncResult.CANCELLED; - return new Promise(function(resolve, reject) { - controller.start(FAKE_HOST_PIN, true, function() { - reject('test failed'); - }, function(/** remoting.Error */ e) { - assert.equal(e.getTag(), remoting.Error.Tag.CANCELLED); - assert.equal(unregisterHostByIdSpy.callCount, 1); - assert.equal(unregisterHostByIdSpy.args[0][0], FAKE_HOST_ID); - assert.equal(onLocalHostStartedSpy.callCount, 0); - resolve(null); - }); + return controller.start(FAKE_HOST_PIN, true).then(function() { + throw 'test failed'; + }, function(/** remoting.Error */ e) { + assert.equal(e.getTag(), remoting.Error.Tag.CANCELLED); + assert.equal(unregisterHostByIdSpy.callCount, 1); + assert.equal(unregisterHostByIdSpy.args[0][0], FAKE_HOST_ID); + assert.equal(onLocalHostStartedSpy.callCount, 0); }); }); @@ -425,53 +373,47 @@ stubSignalStrategyConnect(true); mockHostDaemonFacade.startDaemonResult = remoting.HostController.AsyncResult.FAILED; - return new Promise(function(resolve, reject) { - controller.start(FAKE_HOST_PIN, true, function() { - reject('test failed'); - }, function(/** remoting.Error */ e) { - assert.equal(e.getTag(), remoting.Error.Tag.UNEXPECTED); - assert.equal(unregisterHostByIdSpy.callCount, 1); - assert.equal(onLocalHostStartedSpy.callCount, 0); - resolve(null); - }); + return controller.start(FAKE_HOST_PIN, true).then(function() { + throw 'test failed'; + }, function(/** remoting.Error */ e) { + assert.equal(e.getTag(), remoting.Error.Tag.UNEXPECTED); + assert.equal(unregisterHostByIdSpy.callCount, 1); + assert.equal(onLocalHostStartedSpy.callCount, 0); }); }); // Check what happens when the entire host registration process // succeeds. [false, true].forEach(function(/** boolean */ consent) { - QUnit.test('start succeeds(1) with consent=' + consent, function(assert) { + QUnit.test('start with auth code, consent=' + consent, function(assert) { /** @const */ var fakePinHash = fakePinHashFunc(FAKE_HOST_ID, FAKE_HOST_PIN); queueRegistryResponse(assert, true); stubSignalStrategyConnect(true); - return new Promise(function(resolve, reject) { - controller.start(FAKE_HOST_PIN, consent, function() { - assert.equal(getCredentialsFromAuthCodeSpy.callCount, 1); - assert.deepEqual( - getCredentialsFromAuthCodeSpy.args[0][0], - FAKE_AUTH_CODE); - assert.equal(getPinHashSpy.callCount, 1); - assert.deepEqual( - getPinHashSpy.args[0].slice(0, 2), - [FAKE_HOST_ID, FAKE_HOST_PIN]); - assert.equal(unregisterHostByIdSpy.callCount, 0); - assert.equal(onLocalHostStartedSpy.callCount, 1); - assert.equal(startDaemonSpy.callCount, 1); - assert.deepEqual( - startDaemonSpy.args[0].slice(0, 2), - [{ - xmpp_login: FAKE_XMPP_LOGIN, - oauth_refresh_token: FAKE_REFRESH_TOKEN, - host_owner: FAKE_CLIENT_JID.toLowerCase(), - host_owner_email: FAKE_USER_EMAIL, - host_id: FAKE_HOST_ID, - host_name: FAKE_HOST_NAME, - host_secret_hash: fakePinHash, - private_key: FAKE_PRIVATE_KEY - }, consent]); - resolve(null); - }, reject); + return controller.start(FAKE_HOST_PIN, consent).then(function() { + assert.equal(getCredentialsFromAuthCodeSpy.callCount, 1); + assert.deepEqual( + getCredentialsFromAuthCodeSpy.args[0][0], + FAKE_AUTH_CODE); + assert.equal(getPinHashSpy.callCount, 1); + assert.deepEqual( + getPinHashSpy.args[0].slice(0, 2), + [FAKE_HOST_ID, FAKE_HOST_PIN]); + assert.equal(unregisterHostByIdSpy.callCount, 0); + assert.equal(onLocalHostStartedSpy.callCount, 1); + assert.equal(startDaemonSpy.callCount, 1); + assert.deepEqual( + startDaemonSpy.args[0].slice(0, 2), + [{ + xmpp_login: FAKE_XMPP_LOGIN, + oauth_refresh_token: FAKE_REFRESH_TOKEN, + host_owner: FAKE_CLIENT_JID.toLowerCase(), + host_owner_email: FAKE_USER_EMAIL, + host_id: FAKE_HOST_ID, + host_name: FAKE_HOST_NAME, + host_secret_hash: fakePinHash, + private_key: FAKE_PRIVATE_KEY + }, consent]); }); }); }); @@ -479,32 +421,30 @@ // Check alternative host registration without a registry-supplied // auth code. [false, true].forEach(function(/** boolean */ consent) { - QUnit.test('start succeeds(2) with consent=' + consent, function(assert) { + QUnit.test('start without auth code, consent=' + consent, function(assert) { /** @const */ var fakePinHash = fakePinHashFunc(FAKE_HOST_ID, FAKE_HOST_PIN); queueRegistryResponse(assert, false); stubSignalStrategyConnect(true); - return new Promise(function(resolve, reject) { - controller.start(FAKE_HOST_PIN, consent, function() { - assert.equal(getPinHashSpy.callCount, 1); - assert.deepEqual( - getPinHashSpy.args[0].slice(0, 2), - [FAKE_HOST_ID, FAKE_HOST_PIN]); - assert.equal(unregisterHostByIdSpy.callCount, 0); - assert.equal(onLocalHostStartedSpy.callCount, 1); - assert.equal(startDaemonSpy.callCount, 1); - assert.deepEqual( - startDaemonSpy.args[0].slice(0, 2), - [{ - xmpp_login: FAKE_USER_EMAIL, - oauth_refresh_token: FAKE_REFRESH_TOKEN, - host_id: FAKE_HOST_ID, - host_name: FAKE_HOST_NAME, - host_secret_hash: fakePinHash, - private_key: FAKE_PRIVATE_KEY - }, consent]); - resolve(null); - }, reject); + return controller.start(FAKE_HOST_PIN, consent).then(function() { + assert.equal(getCredentialsFromAuthCodeSpy.callCount, 0); + assert.equal(getPinHashSpy.callCount, 1); + assert.deepEqual( + getPinHashSpy.args[0].slice(0, 2), + [FAKE_HOST_ID, FAKE_HOST_PIN]); + assert.equal(unregisterHostByIdSpy.callCount, 0); + assert.equal(onLocalHostStartedSpy.callCount, 1); + assert.equal(startDaemonSpy.callCount, 1); + assert.deepEqual( + startDaemonSpy.args[0].slice(0, 2), + [{ + xmpp_login: FAKE_USER_EMAIL, + oauth_refresh_token: FAKE_REFRESH_TOKEN, + host_id: FAKE_HOST_ID, + host_name: FAKE_HOST_NAME, + host_secret_hash: fakePinHash, + private_key: FAKE_PRIVATE_KEY + }, consent]); }); }); }); @@ -674,8 +614,8 @@ // Check what happens when getLocalHostState reports no plugin. QUnit.test('getLocalHostState with no plugin', function(assert) { - sinon.stub(mockHostDaemonFacade, 'getDaemonState'). - callsArgWith(1, new remoting.Error(remoting.Error.Tag.MISSING_PLUGIN)); + sinon.stub(mockHostDaemonFacade, 'getDaemonState').returns( + Promise.reject(new remoting.Error(remoting.Error.Tag.MISSING_PLUGIN))); return new Promise(function(resolve, reject) { controller.getLocalHostState(function( /** remoting.HostController.State */ state) { @@ -729,8 +669,8 @@ }); }); -// Tests omitted for getPairedClients, deletePairedClient, and -// clearPairedClients because they simply call through to +// Tests omitted for hasFeature, getPairedClients, deletePairedClient, +// and clearPairedClients because they simply call through to // HostDaemonFacade. })();
diff --git a/remoting/webapp/crd/js/host_daemon_facade.js b/remoting/webapp/crd/js/host_daemon_facade.js index 6b9d9c1..0596b57 100644 --- a/remoting/webapp/crd/js/host_daemon_facade.js +++ b/remoting/webapp/crd/js/host_daemon_facade.js
@@ -84,54 +84,46 @@ * @private */ remoting.HostDaemonFacade.prototype.connectNative_ = function() { - /** - * @this {remoting.HostDaemonFacade} - * @param {function(?):void} resolve - * @param {function(*):void} reject - */ - var connect = function(resolve, reject) { - try { - this.port_ = chrome.runtime.connectNative( - 'com.google.chrome.remote_desktop'); - this.port_.onMessage.addListener(this.onIncomingMessageCallback_); - this.port_.onDisconnect.addListener(this.onDisconnectCallback_); - this.postMessageInternal_({type: 'hello'}, resolve, reject); - } catch (/** @type {*} */ err) { - console.log('Native Messaging initialization failed: ', err); - reject(false); - } - }; - - return new Promise(connect.bind(this)); + try { + this.port_ = chrome.runtime.connectNative( + 'com.google.chrome.remote_desktop'); + this.port_.onMessage.addListener(this.onIncomingMessageCallback_); + this.port_.onDisconnect.addListener(this.onDisconnectCallback_); + return this.postMessageInternal_({type: 'hello'}); + } catch (/** @type {*} */ err) { + console.log('Native Messaging initialization failed: ', err); + throw remoting.Error.unexpected(); + } }; /** * Type used for entries of |pendingReplies_| list. * * @param {string} type Type of the originating request. - * @param {function(...):void} onDone Response callback. Parameters depend on - * the request type. - * @param {function(!remoting.Error):void} onError Callback to call on error. + * @param {!base.Deferred} deferred Used to communicate returns back + * to the caller. * @constructor */ -remoting.HostDaemonFacade.PendingReply = function(type, onDone, onError) { +remoting.HostDaemonFacade.PendingReply = function(type, deferred) { + /** @const */ this.type = type; - this.onDone = onDone; - this.onError = onError; + + /** @const */ + this.deferred = deferred; }; /** * @param {remoting.HostController.Feature} feature The feature to test for. - * @param {function(boolean):void} onDone Callback to return result. - * @return {boolean} True if the implementation supports the named feature. + * @return {!Promise<boolean>} True if the implementation supports the + * named feature. */ -remoting.HostDaemonFacade.prototype.hasFeature = function(feature, onDone) { +remoting.HostDaemonFacade.prototype.hasFeature = function(feature) { /** @type {remoting.HostDaemonFacade} */ var that = this; - this.initialize_().then(function() { - onDone(that.supportedFeatures_.indexOf(feature) >= 0); - }, function (){ - onDone(false); + return this.initialize_().then(function() { + return that.supportedFeatures_.indexOf(feature) >= 0; + }, function () { + return false; }); }; @@ -139,42 +131,38 @@ * Initializes that the Daemon if necessary and posts the supplied message. * * @param {{type: string}} message The message to post. - * @param {function(...):void} onDone The callback, if any, to be triggered - * on response. - * @param {function(!remoting.Error):void} onError Callback to call on error. + * @return {!Promise} * @private */ remoting.HostDaemonFacade.prototype.postMessage_ = - function(message, onDone, onError) { + function(message) { /** @type {remoting.HostDaemonFacade} */ var that = this; - this.initialize_().then(function() { - that.postMessageInternal_(message, onDone, onError); + return this.initialize_().then(function() { + return that.postMessageInternal_(message); }, function() { - onError(that.error_); + throw that.error_; }); }; /** - * Attaches a new ID to the supplied message, and posts it to the Native - * Messaging port, adding |onDone| to the list of pending replies. - * |message| should have its 'type' field set, and any other fields set - * depending on the message type. + * Attaches a new ID to the supplied message, and posts it to the + * Native Messaging port, adding a Deferred object to the list of + * pending replies. |message| should have its 'type' field set, and + * any other fields set depending on the message type. * * @param {{type: string}} message The message to post. - * @param {function(...):void} onDone The callback, if any, to be triggered - * on response. - * @param {function(!remoting.Error):void} onError Callback to call on error. - * @return {void} Nothing. + * @return {!Promise} * @private */ -remoting.HostDaemonFacade.prototype.postMessageInternal_ = - function(message, onDone, onError) { +remoting.HostDaemonFacade.prototype.postMessageInternal_ = function(message) { var id = this.nextId_++; message['id'] = id; + var deferred = new base.Deferred(); this.pendingReplies_[id] = new remoting.HostDaemonFacade.PendingReply( - message.type + 'Response', onDone, onError); + message.type + 'Response', deferred); this.port_.postMessage(message); + return deferred.promise(); }; /** @@ -204,24 +192,34 @@ throw 'Expected reply type: ' + reply.type + ', got: ' + type; } - this.handleIncomingMessage_(message, reply.onDone); + reply.deferred.resolve(this.handleIncomingMessage_(message)); } catch (/** @type {*} */ e) { console.error('Error while processing native message', e); - reply.onError(remoting.Error.unexpected()); + reply.deferred.reject(remoting.Error.unexpected()); } -} +}; /** * Handler for incoming Native Messages. * + * TODO(jrw) Consider refactoring so each method handles its own + * response, e.g.: + * + * remoting.HostDaemonFacade.prototype.generateKeyPair = function() { + * this.postMessage_({type: 'generateKeyPair'}).then(function(message) { + * return { + * privateKey: base.getStringAttr(message, 'privateKey'), + * publicKey: base.getStringAttr(message, 'publicKey') + * } + * }); + * }; + * * @param {Object} message The received message. - * @param {function(...):void} onDone Function to call when we're done - * processing the message. - * @return {void} Nothing. + * @return {*} * @private */ remoting.HostDaemonFacade.prototype.handleIncomingMessage_ = - function(message, onDone) { + function(message) { var type = base.getStringAttr(message, 'type'); switch (type) { @@ -231,81 +229,70 @@ // Those versions default to the empty list of supported features. this.supportedFeatures_ = base.getArrayAttr(message, 'supportedFeatures', []); - onDone(); - break; + return null; case 'getHostNameResponse': - onDone(base.getStringAttr(message, 'hostname')); - break; + return base.getStringAttr(message, 'hostname'); case 'getPinHashResponse': - onDone(base.getStringAttr(message, 'hash')); - break; + return base.getStringAttr(message, 'hash'); case 'generateKeyPairResponse': - var privateKey = base.getStringAttr(message, 'privateKey'); - var publicKey = base.getStringAttr(message, 'publicKey'); - onDone(privateKey, publicKey); - break; + return { + privateKey: base.getStringAttr(message, 'privateKey'), + publicKey: base.getStringAttr(message, 'publicKey') + }; case 'updateDaemonConfigResponse': - var result = remoting.HostController.AsyncResult.fromString( + return remoting.HostController.AsyncResult.fromString( base.getStringAttr(message, 'result')); - onDone(result); - break; case 'getDaemonConfigResponse': - onDone(base.getObjectAttr(message, 'config')); - break; + return base.getObjectAttr(message, 'config'); case 'getUsageStatsConsentResponse': - var supported = base.getBooleanAttr(message, 'supported'); - var allowed = base.getBooleanAttr(message, 'allowed'); - var setByPolicy = base.getBooleanAttr(message, 'setByPolicy'); - onDone(supported, allowed, setByPolicy); - break; + return { + supported: base.getBooleanAttr(message, 'supported'), + allowed: base.getBooleanAttr(message, 'allowed'), + setByPolicy: base.getBooleanAttr(message, 'setByPolicy') + }; case 'startDaemonResponse': case 'stopDaemonResponse': - var result = remoting.HostController.AsyncResult.fromString( + return remoting.HostController.AsyncResult.fromString( base.getStringAttr(message, 'result')); - onDone(result); - break; case 'getDaemonStateResponse': - var state = remoting.HostController.State.fromString( + return remoting.HostController.State.fromString( base.getStringAttr(message, 'state')); - onDone(state); - break; case 'getPairedClientsResponse': var pairedClients = remoting.PairedClient.convertToPairedClientArray( message['pairedClients']); if (pairedClients != null) { - onDone(pairedClients); + return pairedClients; } else { throw 'No paired clients!'; } - break; case 'clearPairedClientsResponse': case 'deletePairedClientResponse': - onDone(base.getBooleanAttr(message, 'result')); - break; + return base.getBooleanAttr(message, 'result'); case 'getHostClientIdResponse': - onDone(base.getStringAttr(message, 'clientId')); - break; + return base.getStringAttr(message, 'clientId'); case 'getCredentialsFromAuthCodeResponse': var userEmail = base.getStringAttr(message, 'userEmail'); var refreshToken = base.getStringAttr(message, 'refreshToken'); if (userEmail && refreshToken) { - onDone(userEmail, refreshToken); + return { + userEmail: userEmail, + refreshToken: refreshToken + }; } else { throw 'Missing userEmail or refreshToken'; } - break; default: throw 'Unexpected native message: ' + message; @@ -334,20 +321,17 @@ this.pendingReplies_ = {}; for (var id in pendingReplies) { var num_id = parseInt(id, 10); - pendingReplies[num_id].onError(this.error_); + pendingReplies[num_id].deferred.reject(this.error_); } } /** * Gets local hostname. * - * @param {function(string):void} onDone Callback to return result. - * @param {function(!remoting.Error):void} onError Callback to call on error. - * @return {void} Nothing. + * @return {!Promise<string>} */ -remoting.HostDaemonFacade.prototype.getHostName = - function(onDone, onError) { - this.postMessage_({type: 'getHostName'}, onDone, onError); +remoting.HostDaemonFacade.prototype.getHostName = function() { + return this.postMessage_({type: 'getHostName'}); }; /** @@ -356,17 +340,14 @@ * * @param {string} hostId The host ID. * @param {string} pin The PIN. - * @param {function(string):void} onDone Callback to return result. - * @param {function(!remoting.Error):void} onError Callback to call on error. - * @return {void} Nothing. + * @return {!Promise<string>} */ -remoting.HostDaemonFacade.prototype.getPinHash = - function(hostId, pin, onDone, onError) { - this.postMessage_({ +remoting.HostDaemonFacade.prototype.getPinHash = function(hostId, pin) { + return this.postMessage_({ type: 'getPinHash', hostId: hostId, pin: pin - }, onDone, onError); + }); }; /** @@ -374,13 +355,10 @@ * when the key is generated. The key is returned in format understood by the * host (PublicKeyInfo structure encoded with ASN.1 DER, and then BASE64). * - * @param {function(string, string):void} onDone Callback to return result. - * @param {function(!remoting.Error):void} onError Callback to call on error. - * @return {void} Nothing. + * @return {!Promise<remoting.KeyPair>} */ -remoting.HostDaemonFacade.prototype.generateKeyPair = - function(onDone, onError) { - this.postMessage_({type: 'generateKeyPair'}, onDone, onError); +remoting.HostDaemonFacade.prototype.generateKeyPair = function() { + return this.postMessage_({type: 'generateKeyPair'}); }; /** @@ -391,51 +369,40 @@ * includes these parameters. Changes take effect before the callback * is called. * - * TODO(jrw): Consider eliminating onError callback. + * TODO(jrw): Consider conversion exceptions to AsyncResult values. * * @param {Object} config The new config parameters. - * @param {function(remoting.HostController.AsyncResult):void} onDone - * Callback to be called when finished. - * @param {function(!remoting.Error):void} onError Callback to call on error. - * @return {void} Nothing. + * @return {!Promise<remoting.HostController.AsyncResult>} */ -remoting.HostDaemonFacade.prototype.updateDaemonConfig = - function(config, onDone, onError) { - this.postMessage_({ +remoting.HostDaemonFacade.prototype.updateDaemonConfig = function(config) { + return this.postMessage_({ type: 'updateDaemonConfig', config: config - }, onDone, onError); + }); }; /** * Loads daemon config. The config is passed as a JSON formatted string to the * callback. - * - * @param {function(Object):void} onDone Callback to return result. - * @param {function(!remoting.Error):void} onError Callback to call on error. - * @return {void} Nothing. + * @return {!Promise<Object>} */ -remoting.HostDaemonFacade.prototype.getDaemonConfig = - function(onDone, onError) { - this.postMessage_({type: 'getDaemonConfig'}, onDone, onError); +remoting.HostDaemonFacade.prototype.getDaemonConfig = function() { + return this.postMessage_({type: 'getDaemonConfig'}); }; /** - * Retrieves daemon version. The version is passed to onDone as a dotted decimal + * Retrieves daemon version. The version is returned as a dotted decimal * string of the form major.minor.build.patch. * - * @param {function(string):void} onDone Callback to be called to return result. - * @param {function(!remoting.Error):void} onError Callback to call on error. - * @return {void} + * @return {!Promise<string>} */ -remoting.HostDaemonFacade.prototype.getDaemonVersion = - function(onDone, onError) { +remoting.HostDaemonFacade.prototype.getDaemonVersion = function() { /** @type {remoting.HostDaemonFacade} */ var that = this; - this.initialize_().then(function() { - onDone(that.version_); + return this.initialize_().then(function() { + return that.version_; }, function() { - onError(that.error_); + throw that.error_; }); }; @@ -443,126 +410,99 @@ * Get the user's consent to crash reporting. The consent flags are passed to * the callback as booleans: supported, allowed, set-by-policy. * - * @param {function(boolean, boolean, boolean):void} onDone Callback to return - * result. - * @param {function(!remoting.Error):void} onError Callback to call on error. - * @return {void} Nothing. + * @return {!Promise<remoting.UsageStatsConsent>} */ -remoting.HostDaemonFacade.prototype.getUsageStatsConsent = - function(onDone, onError) { - this.postMessage_({type: 'getUsageStatsConsent'}, onDone, onError); +remoting.HostDaemonFacade.prototype.getUsageStatsConsent = function() { + return this.postMessage_({type: 'getUsageStatsConsent'}); }; /** * Starts the daemon process with the specified configuration. * - * TODO(jrw): Consider eliminating onError callback. + * TODO(jrw): Consider conversion exceptions to AsyncResult values. * * @param {Object} config Host configuration. * @param {boolean} consent Consent to report crash dumps. - * @param {function(remoting.HostController.AsyncResult):void} onDone - * Callback to return result. - * @param {function(!remoting.Error):void} onError Callback to call on error. - * @return {void} Nothing. + * @return {!Promise<remoting.HostController.AsyncResult>} */ -remoting.HostDaemonFacade.prototype.startDaemon = - function(config, consent, onDone, onError) { - this.postMessage_({ +remoting.HostDaemonFacade.prototype.startDaemon = function(config, consent) { + return this.postMessage_({ type: 'startDaemon', config: config, consent: consent - }, onDone, onError); + }); }; /** * Stops the daemon process. * - * TODO(jrw): Consider eliminating onError callback. + * TODO(jrw): Consider conversion exceptions to AsyncResult values. * - * @param {function(remoting.HostController.AsyncResult):void} onDone - * Callback to return result. - * @param {function(!remoting.Error):void} onError Callback to call on error. - * @return {void} Nothing. + * @return {!Promise<remoting.HostController.AsyncResult>} */ remoting.HostDaemonFacade.prototype.stopDaemon = - function(onDone, onError) { - this.postMessage_({type: 'stopDaemon'}, onDone, onError); + function() { + return this.postMessage_({type: 'stopDaemon'}); }; /** * Gets the installed/running state of the Host process. * - * @param {function(remoting.HostController.State):void} onDone Callback to -* return result. - * @param {function(!remoting.Error):void} onError Callback to call on error. - * @return {void} Nothing. + * @return {!Promise<remoting.HostController.State>} */ -remoting.HostDaemonFacade.prototype.getDaemonState = - function(onDone, onError) { - this.postMessage_({type: 'getDaemonState'}, onDone, onError); -} +remoting.HostDaemonFacade.prototype.getDaemonState = function() { + return this.postMessage_({type: 'getDaemonState'}); +}; /** * Retrieves the list of paired clients. * - * @param {function(Array<remoting.PairedClient>):void} onDone Callback to - * return result. - * @param {function(!remoting.Error):void} onError Callback to call on error. + * @return {!Promise<Array<remoting.PairedClient>>} */ -remoting.HostDaemonFacade.prototype.getPairedClients = - function(onDone, onError) { - this.postMessage_({type: 'getPairedClients'}, onDone, onError); -} +remoting.HostDaemonFacade.prototype.getPairedClients = function() { + return this.postMessage_({type: 'getPairedClients'}); +}; /** * Clears all paired clients from the registry. * - * @param {function(boolean):void} onDone Callback to be called when finished. - * @param {function(!remoting.Error):void} onError Callback to call on error. + * @return {!Promise<boolean>} */ -remoting.HostDaemonFacade.prototype.clearPairedClients = - function(onDone, onError) { - this.postMessage_({type: 'clearPairedClients'}, onDone, onError); -} +remoting.HostDaemonFacade.prototype.clearPairedClients = function() { + return this.postMessage_({type: 'clearPairedClients'}); +}; /** * Deletes a paired client referenced by client id. * * @param {string} client Client to delete. - * @param {function(boolean):void} onDone Callback to be called when finished. - * @param {function(!remoting.Error):void} onError Callback to call on error. + * @return {!Promise<boolean>} */ -remoting.HostDaemonFacade.prototype.deletePairedClient = - function(client, onDone, onError) { - this.postMessage_({ +remoting.HostDaemonFacade.prototype.deletePairedClient = function(client) { + return this.postMessage_({ type: 'deletePairedClient', clientId: client - }, onDone, onError); -} + }); +}; /** * Gets the API keys to obtain/use service account credentials. * - * @param {function(string):void} onDone Callback to return result. - * @param {function(!remoting.Error):void} onError Callback to call on error. - * @return {void} Nothing. + * @return {!Promise<string>} */ -remoting.HostDaemonFacade.prototype.getHostClientId = - function(onDone, onError) { - this.postMessage_({type: 'getHostClientId'}, onDone, onError); +remoting.HostDaemonFacade.prototype.getHostClientId = function() { + return this.postMessage_({type: 'getHostClientId'}); }; /** * * @param {string} authorizationCode OAuth authorization code. - * @param {function(string, string):void} onDone Callback to return result. - * @param {function(!remoting.Error):void} onError Callback to call on error. - * @return {void} Nothing. + * @return {!Promise<{remoting.XmppCredentials}>} */ remoting.HostDaemonFacade.prototype.getCredentialsFromAuthCode = - function(authorizationCode, onDone, onError) { - this.postMessage_({ + function(authorizationCode) { + return this.postMessage_({ type: 'getCredentialsFromAuthCode', authorizationCode: authorizationCode - }, onDone, onError); + }); };
diff --git a/remoting/webapp/crd/js/host_daemon_facade_unittest.js b/remoting/webapp/crd/js/host_daemon_facade_unittest.js index 0a3cf51..f7f6ad2 100644 --- a/remoting/webapp/crd/js/host_daemon_facade_unittest.js +++ b/remoting/webapp/crd/js/host_daemon_facade_unittest.js
@@ -68,12 +68,9 @@ id: 0, type: 'hello' }); - var done = assert.async(); - it.hasFeature( - remoting.HostController.Feature.PAIRING_REGISTRY, - function onDone(arg) { + return it.hasFeature(remoting.HostController.Feature.PAIRING_REGISTRY). + then(function(arg) { assert.equal(arg, true); - done(); }); }); @@ -89,12 +86,9 @@ id: 0, type: 'hello' }); - var done = assert.async(); - it.hasFeature( - remoting.HostController.Feature.PAIRING_REGISTRY, - function onDone(arg) { + return it.hasFeature(remoting.HostController.Feature.PAIRING_REGISTRY). + then(function(arg) { assert.equal(arg, false); - done(); }); }); @@ -110,15 +104,9 @@ id: 0, type: 'hello' }); - var done = assert.async(); - it.getDaemonVersion( - function onDone(arg) { + return it.getDaemonVersion(). + then(function onDone(arg) { assert.equal(arg, '<daemonVersion>'); - done(); - }, - function onError() { - assert.ok(false); - done(); }); }); @@ -139,36 +127,19 @@ id: 0, type: 'hello' }); - return new Promise(function(resolve, reject) { - it.getDaemonVersion(resolve, reject); - }).then(function() { + it.getDaemonVersion().then(function() { return callback(assert); }); }); } -/** - * A combinator that turns an ordinary 1-argument resolve function - * into a function that accepts multiple arguments and bundles them - * into an array. - * @param {function(*):void} resolve - * @return {function(...*):void} - */ -function resolveMulti(resolve) { - return function() { - resolve(Array.prototype.slice.call(arguments)); - }; -} - postInitTest('getHostName', function(assert) { mockHostResponses.push({ id: 1, type: 'getHostNameResponse', hostname: '<fakeHostName>' }); - return new Promise(function (resolve, reject) { - it.getHostName(resolve, reject); - }).then(function(/** string */ hostName) { + return it.getHostName().then(function(hostName) { assert.deepEqual(postMessageStub.args[1][0], { id: 1, type: 'getHostName' @@ -183,9 +154,7 @@ type: 'getPinHashResponse', hash: '<fakePinHash>' }); - return new Promise(function (resolve, reject) { - it.getPinHash('<hostId>', '<pin>', resolve, reject); - }).then(function(/** string */ hostName) { + return it.getPinHash('<hostId>', '<pin>').then(function(hostName) { assert.deepEqual(postMessageStub.args[1][0], { id: 1, type: 'getPinHash', @@ -203,14 +172,15 @@ privateKey: '<fakePrivateKey>', publicKey: '<fakePublicKey>' }); - return new Promise(function (resolve, reject) { - it.generateKeyPair(resolveMulti(resolve), reject); - }).then(function(/** Array */ result) { + return it.generateKeyPair().then(function(pair) { assert.deepEqual(postMessageStub.args[1][0], { id: 1, type: 'generateKeyPair' }); - assert.deepEqual(result, ['<fakePrivateKey>', '<fakePublicKey>']); + assert.deepEqual(pair, { + privateKey: '<fakePrivateKey>', + publicKey: '<fakePublicKey>' + }); }); }); @@ -220,9 +190,9 @@ type: 'updateDaemonConfigResponse', result: 'OK' }); - return new Promise(function (resolve, reject) { - it.updateDaemonConfig({ fakeDaemonConfig: true }, resolve, reject); - }).then(function(/** * */ result) { + return it.updateDaemonConfig({ + fakeDaemonConfig: true + }).then(function(result) { assert.deepEqual(postMessageStub.args[1][0], { id: 1, type: 'updateDaemonConfig', @@ -238,9 +208,7 @@ type: 'getDaemonConfigResponse', config: { fakeDaemonConfig: true } }); - return new Promise(function (resolve, reject) { - it.getDaemonConfig(resolve, reject); - }).then(function(/** * */ result) { + return it.getDaemonConfig().then(function(result) { assert.deepEqual(postMessageStub.args[1][0], { id: 1, type: 'getDaemonConfig' @@ -261,14 +229,16 @@ allowed: allowed, setByPolicy: setByPolicy }); - return new Promise(function (resolve, reject) { - it.getUsageStatsConsent(resolveMulti(resolve), reject); - }).then(function(/** * */ result) { + return it.getUsageStatsConsent().then(function(result) { assert.deepEqual(postMessageStub.args[1][0], { id: 1, type: 'getUsageStatsConsent' }); - assert.deepEqual(result, [supported, allowed, setByPolicy]); + assert.deepEqual(result, { + supported: supported, + allowed: allowed, + setByPolicy: setByPolicy + }); }); }); }); @@ -280,9 +250,9 @@ type: 'startDaemonResponse', result: 'FAILED' }); - return new Promise(function (resolve, reject) { - it.startDaemon({ fakeConfig: true }, consent, resolve, reject); - }).then(function(/** * */ result) { + return it.startDaemon({ + fakeConfig: true + }, consent).then(function(result) { assert.deepEqual(postMessageStub.args[1][0], { id: 1, type: 'startDaemon', @@ -300,9 +270,7 @@ type: 'stopDaemonResponse', result: 'CANCELLED' }); - return new Promise(function (resolve, reject) { - it.stopDaemon(resolve, reject); - }).then(function(/** * */ result) { + return it.stopDaemon().then(function(result) { assert.deepEqual(postMessageStub.args[1][0], { id: 1, type: 'stopDaemon' @@ -331,9 +299,7 @@ type: 'getPairedClientsResponse', pairedClients: [client0, client1] }); - return new Promise(function (resolve, reject) { - it.getPairedClients(resolve, reject); - }).then(function(/** Array<remoting.PairedClient> */ result) { + return it.getPairedClients().then(function(result) { assert.deepEqual(postMessageStub.args[1][0], { id: 1, type: 'getPairedClients' @@ -359,9 +325,7 @@ type: 'clearPairedClientsResponse', result: deleted }); - return new Promise(function (resolve, reject) { - it.clearPairedClients(resolve, reject); - }).then(function(/** * */ result) { + return it.clearPairedClients().then(function(result) { assert.deepEqual(postMessageStub.args[1][0], { id: 1, type: 'clearPairedClients' @@ -378,9 +342,7 @@ type: 'deletePairedClientResponse', result: deleted }); - return new Promise(function (resolve, reject) { - it.deletePairedClient('<fakeClientId>', resolve, reject); - }).then(function(/** * */ result) { + return it.deletePairedClient('<fakeClientId>').then(function(result) { assert.deepEqual(postMessageStub.args[1][0], { id: 1, type: 'deletePairedClient', @@ -397,9 +359,7 @@ type: 'getHostClientIdResponse', clientId: '<fakeClientId>' }); - return new Promise(function (resolve, reject) { - it.getHostClientId(resolve, reject); - }).then(function(/** * */ result) { + return it.getHostClientId().then(function(result) { assert.deepEqual(postMessageStub.args[1][0], { id: 1, type: 'getHostClientId' @@ -415,17 +375,17 @@ userEmail: '<fakeUserEmail>', refreshToken: '<fakeRefreshToken>' }); - return new Promise(function (resolve, reject) { - it.getCredentialsFromAuthCode( - '<fakeAuthCode>', resolveMulti(resolve), reject); - }).then(function(/** * */ result) { + return it.getCredentialsFromAuthCode('<fakeAuthCode>').then(function(result) { assert.deepEqual(postMessageStub.args[1][0], { id: 1, type: 'getCredentialsFromAuthCode', authorizationCode: '<fakeAuthCode>' }); - assert.deepEqual(result, ['<fakeUserEmail>', '<fakeRefreshToken>']); + assert.deepEqual(result, { + userEmail: '<fakeUserEmail>', + refreshToken: '<fakeRefreshToken>' + }); }); }); -})(); \ No newline at end of file +})();
diff --git a/remoting/webapp/crd/js/host_setup_dialog.js b/remoting/webapp/crd/js/host_setup_dialog.js index 40cc7d5..df0b7e3 100644 --- a/remoting/webapp/crd/js/host_setup_dialog.js +++ b/remoting/webapp/crd/js/host_setup_dialog.js
@@ -187,23 +187,20 @@ var that = this; /** - * @param {boolean} supported True if crash dump reporting is supported by - * the host. - * @param {boolean} allowed True if crash dump reporting is allowed. - * @param {boolean} set_by_policy True if crash dump reporting is controlled - * by policy. + * @param {remoting.UsageStatsConsent} consent */ - function onGetConsent(supported, allowed, set_by_policy) { + function onGetConsent(consent) { // Hide the usage stats check box if it is not supported or the policy // doesn't allow usage stats collection. var checkBoxLabel = that.usageStats_.querySelector('.checkbox-label'); - that.usageStats_.hidden = !supported || (set_by_policy && !allowed); - that.usageStatsCheckbox_.checked = allowed; + that.usageStats_.hidden = !consent.supported || + (consent.setByPolicy && !consent.allowed); + that.usageStatsCheckbox_.checked = consent.allowed; - that.usageStatsCheckbox_.disabled = set_by_policy; - checkBoxLabel.classList.toggle('disabled', set_by_policy); + that.usageStatsCheckbox_.disabled = consent.setByPolicy; + checkBoxLabel.classList.toggle('disabled', consent.setByPolicy); - if (set_by_policy) { + if (consent.setByPolicy) { that.usageStats_.title = l10n.getTranslationOrError( /*i18n-content*/ 'SETTING_MANAGED_BY_POLICY'); } else { @@ -223,7 +220,8 @@ // known. this.usageStatsCheckbox_.disabled = true; - this.hostController_.getConsent(onGetConsent, onError); + this.hostController_.getConsent().then( + onGetConsent, remoting.Error.handler(onError)); var flow = [ remoting.HostSetupFlow.State.INSTALL_HOST, @@ -427,8 +425,11 @@ } } - this.hostController_.start(this.flow_.pin, this.flow_.consent, onHostStarted, - onError); + this.hostController_.start(this.flow_.pin, this.flow_.consent).then( + onHostStarted + ).catch( + remoting.Error.handler(onError) + ); }; remoting.HostSetupDialog.prototype.updatePin_ = function() {
diff --git a/remoting/webapp/crd/js/it2me_activity.js b/remoting/webapp/crd/js/it2me_activity.js index e6eac18..98b4bf5 100644 --- a/remoting/webapp/crd/js/it2me_activity.js +++ b/remoting/webapp/crd/js/it2me_activity.js
@@ -15,13 +15,10 @@ var ACCESS_CODE_LENGTH = SUPPORT_ID_LENGTH + HOST_SECRET_LENGTH; /** - * @param {remoting.SessionConnector} sessionConnector * @constructor * @implements {remoting.Activity} */ -remoting.It2MeActivity = function(sessionConnector) { - /** @private */ - this.sessionConnector_ = sessionConnector; +remoting.It2MeActivity = function() { /** @private */ this.hostId_ = ''; /** @private */ @@ -34,9 +31,15 @@ form, form.querySelector('#access-code-entry'), form.querySelector('#cancel-access-code-button')); + + /** @private {remoting.DesktopRemotingActivity} */ + this.desktopActivity_ = null; }; -remoting.It2MeActivity.prototype.dispose = function() {}; +remoting.It2MeActivity.prototype.dispose = function() { + base.dispose(this.desktopActivity_); + this.desktopActivity_ = null; +}; remoting.It2MeActivity.prototype.start = function() { var that = this; @@ -51,10 +54,7 @@ }).then(function(/** !remoting.Xhr.Response */ response) { return that.onHostInfo_(response); }).then(function(/** remoting.Host */ host) { - that.sessionConnector_.connect( - remoting.Application.Mode.IT2ME, - host, - new remoting.CredentialsProvider({ accessCode: that.passCode_ })); + that.connect_(host); }).catch(function(/** remoting.Error */ error) { if (error.hasTag(remoting.Error.Tag.CANCELLED)) { remoting.setMode(remoting.AppMode.HOME); @@ -93,6 +93,11 @@ this.showFinishDialog_(remoting.AppMode.CLIENT_CONNECT_FAILED_IT2ME); }; +/** @return {remoting.DesktopRemotingActivity} */ +remoting.It2MeActivity.prototype.getDesktopActivityForTesting = function() { + return this.desktopActivity_; +}; + /** * @param {remoting.AppMode} mode * @private @@ -170,6 +175,22 @@ }; /** + * @param {remoting.Host} host + * @private + */ +remoting.It2MeActivity.prototype.connect_ = function(host) { + base.dispose(this.desktopActivity_); + this.desktopActivity_ = new remoting.DesktopRemotingActivity(this); + var sessionConnector = remoting.SessionConnector.factory.createConnector( + document.getElementById('client-container'), + remoting.app_capabilities(), + this.desktopActivity_); + sessionConnector.connect( + remoting.Application.Mode.IT2ME, host, + new remoting.CredentialsProvider({ accessCode: this.passCode_ })); +}; + +/** * TODO(jrw): Replace with remoting.Error.fromHttpStatus. * @param {number} error An HTTP error code returned by the support-hosts * endpoint.
diff --git a/remoting/webapp/crd/js/me2me_activity.js b/remoting/webapp/crd/js/me2me_activity.js index 6ebf4ba..7dac1ed 100644 --- a/remoting/webapp/crd/js/me2me_activity.js +++ b/remoting/webapp/crd/js/me2me_activity.js
@@ -10,18 +10,15 @@ 'use strict'; /** - * @param {remoting.SessionConnector} sessionConnector * @param {remoting.Host} host * * @constructor * @implements {remoting.Activity} */ -remoting.Me2MeActivity = function(sessionConnector, host) { +remoting.Me2MeActivity = function(host) { /** @private */ this.host_ = host; /** @private */ - this.connector_ = sessionConnector; - /** @private */ this.pinDialog_ = new remoting.PinDialog(document.getElementById('pin-dialog'), host); /** @private */ @@ -33,9 +30,15 @@ /** @private {remoting.SmartReconnector} */ this.reconnector_ = null; + + /** @private {remoting.DesktopRemotingActivity} */ + this.desktopActivity_ = null; }; -remoting.Me2MeActivity.prototype.dispose = function() {}; +remoting.Me2MeActivity.prototype.dispose = function() { + base.dispose(this.desktopActivity_); + this.desktopActivity_ = null; +}; remoting.Me2MeActivity.prototype.start = function() { var webappVersion = chrome.runtime.getManifest().version; @@ -52,13 +55,36 @@ }); }; +/** @return {remoting.DesktopRemotingActivity} */ +remoting.Me2MeActivity.prototype.getDesktopActivity = function() { + return this.desktopActivity_; +}; + /** * @param {boolean} suppressHostOfflineError * @private */ remoting.Me2MeActivity.prototype.connect_ = function(suppressHostOfflineError) { remoting.setMode(remoting.AppMode.CLIENT_CONNECTING); + base.dispose(this.desktopActivity_); + this.desktopActivity_ = new remoting.DesktopRemotingActivity(this); + var connector = remoting.SessionConnector.factory.createConnector( + document.getElementById('client-container'), + remoting.app_capabilities(), + this.desktopActivity_); + + connector.connect( + remoting.Application.Mode.ME2ME, + this.host_, this.createCredentialsProvider_(), suppressHostOfflineError); +}; + +/** + * @return {remoting.CredentialsProvider} + * @private + */ +remoting.Me2MeActivity.prototype.createCredentialsProvider_ = function() { var host = this.host_; + var that = this; /** * @param {string} tokenUrl Token-issue URL received from the host. @@ -74,7 +100,6 @@ thirdPartyTokenFetcher.fetchToken(); }; - var that = this; /** * @param {boolean} supportsPairing * @param {function(string):void} onPinFetched @@ -89,17 +114,12 @@ }); }; - var pairingInfo = /** @type{remoting.PairingInfo} */ ( - base.deepCopy(host.options.pairingInfo)); - var credentialsProvider = new remoting.CredentialsProvider({ + return new remoting.CredentialsProvider({ fetchPin: requestPin, - pairingInfo: pairingInfo, + pairingInfo: /** @type{remoting.PairingInfo} */ ( + base.deepCopy(host.options.pairingInfo)), fetchThirdPartyToken: fetchThirdPartyToken }); - - this.connector_.connect( - remoting.Application.Mode.ME2ME, - host, credentialsProvider, suppressHostOfflineError); }; /** @@ -135,12 +155,12 @@ this.retryOnHostOffline_ = true; var plugin = connectionInfo.plugin(); - if (remoting.app.hasCapability(remoting.ClientSession.Capability.CAST)) { + var session = connectionInfo.session(); + if (session.hasCapability(remoting.ClientSession.Capability.CAST)) { plugin.extensions().register(new remoting.CastExtensionHandler()); } plugin.extensions().register(new remoting.GnubbyAuthHandler()); - this.pinDialog_.requestPairingIfNecessary(connectionInfo.plugin(), - this.connector_); + this.pinDialog_.requestPairingIfNecessary(connectionInfo.plugin()); base.dispose(this.reconnector_); this.reconnector_ = new remoting.SmartReconnector( @@ -265,10 +285,8 @@ /** * @param {remoting.ClientPlugin} plugin - * @param {remoting.SessionConnector} connector */ -remoting.PinDialog.prototype.requestPairingIfNecessary = - function(plugin, connector) { +remoting.PinDialog.prototype.requestPairingIfNecessary = function(plugin) { if (this.pairingCheckbox_.checked) { var that = this; /**
diff --git a/remoting/webapp/crd/js/mock_host_daemon_facade.js b/remoting/webapp/crd/js/mock_host_daemon_facade.js index f7ee1ef..f404df6 100644 --- a/remoting/webapp/crd/js/mock_host_daemon_facade.js +++ b/remoting/webapp/crd/js/mock_host_daemon_facade.js
@@ -87,29 +87,25 @@ /** * @param {remoting.HostController.Feature} feature - * @param {function(boolean):void} onDone - * @return {boolean} + * @return {!Promise<boolean>} */ -remoting.MockHostDaemonFacade.prototype.hasFeature = function(feature, onDone) { +remoting.MockHostDaemonFacade.prototype.hasFeature = function(feature) { var that = this; - Promise.resolve().then(function() { - onDone(that.features.indexOf(feature) >= 0); + return Promise.resolve().then(function() { + return that.features.indexOf(feature) >= 0; }); }; /** - * @param {function(string):void} onDone - * @param {function(!remoting.Error):void} onError - * @return {void} + * @return {!Promise<string>} */ -remoting.MockHostDaemonFacade.prototype.getHostName = - function(onDone, onError) { +remoting.MockHostDaemonFacade.prototype.getHostName = function() { var that = this; - Promise.resolve().then(function() { + return Promise.resolve().then(function() { if (that.hostName === null) { - onError(remoting.Error.unexpected('getHostName')); + throw remoting.Error.unexpected('getHostName'); } else { - onDone(that.hostName); + return that.hostName; } }); }; @@ -117,116 +113,102 @@ /** * @param {string} hostId * @param {string} pin - * @param {function(string):void} onDone - * @param {function(!remoting.Error):void} onError - * @return {void} + * @return {!Promise<string>} */ -remoting.MockHostDaemonFacade.prototype.getPinHash = - function(hostId, pin, onDone, onError) { +remoting.MockHostDaemonFacade.prototype.getPinHash = function(hostId, pin) { var that = this; - Promise.resolve().then(function() { + return Promise.resolve().then(function() { if (that.pinHashFunc === null) { - onError(remoting.Error.unexpected('getPinHash')); + throw remoting.Error.unexpected('getPinHash'); } else { - onDone(that.pinHashFunc(hostId, pin)); + return that.pinHashFunc(hostId, pin); } }); }; /** - * @param {function(string, string):void} onDone - * @param {function(!remoting.Error):void} onError - * @return {void} + * @return {!Promise<{privateKey:string, publicKey:string}>} */ -remoting.MockHostDaemonFacade.prototype.generateKeyPair = - function(onDone, onError) { +remoting.MockHostDaemonFacade.prototype.generateKeyPair = function() { var that = this; - Promise.resolve().then(function() { + return Promise.resolve().then(function() { if (that.privateKey === null || that.publicKey === null) { - onError(remoting.Error.unexpected('generateKeyPair')); + throw remoting.Error.unexpected('generateKeyPair'); } else { - onDone(that.privateKey, that.publicKey); + return { + privateKey: that.privateKey, + publicKey: that.publicKey + }; } }); }; /** - * @param {Object} config - * @param {function(remoting.HostController.AsyncResult):void} onDone - * @param {function(!remoting.Error):void} onError - * @return {void} + * @param {Object} config The new config parameters. + * @return {!Promise<remoting.HostController.AsyncResult>} */ -remoting.MockHostDaemonFacade.prototype.updateDaemonConfig = - function(config, onDone, onError) { +remoting.MockHostDaemonFacade.prototype.updateDaemonConfig = function(config) { var that = this; - Promise.resolve().then(function() { + return Promise.resolve().then(function() { if (that.daemonConfig === null || that.updateDaemonConfigResult === null || 'host_id' in config || 'xmpp_login' in config) { - onError(remoting.Error.unexpected('updateDaemonConfig')); + throw remoting.Error.unexpected('updateDaemonConfig'); } else if (that.updateDaemonConfigResult != remoting.HostController.AsyncResult.OK) { - onDone(that.updateDaemonConfigResult); + return that.updateDaemonConfigResult; } else { base.mix(that.daemonConfig, config); - onDone(remoting.HostController.AsyncResult.OK); + return remoting.HostController.AsyncResult.OK; } }); }; /** - * @param {function(Object):void} onDone - * @param {function(!remoting.Error):void} onError - * @return {void} + * @return {!Promise<Object>} */ -remoting.MockHostDaemonFacade.prototype.getDaemonConfig = - function(onDone, onError) { +remoting.MockHostDaemonFacade.prototype.getDaemonConfig = function() { var that = this; - Promise.resolve().then(function() { + return Promise.resolve().then(function() { if (that.daemonConfig === null) { - onError(remoting.Error.unexpected('getDaemonConfig')); + throw remoting.Error.unexpected('getDaemonConfig'); } else { - onDone(that.daemonConfig); + return that.daemonConfig; } }); }; /** - * @param {function(string):void} onDone - * @param {function(!remoting.Error):void} onError - * @return {void} + * @return {!Promise<string>} */ -remoting.MockHostDaemonFacade.prototype.getDaemonVersion = - function(onDone, onError) { +remoting.MockHostDaemonFacade.prototype.getDaemonVersion = function() { var that = this; - Promise.resolve().then(function() { + return Promise.resolve().then(function() { if (that.daemonVersion === null) { - onError(remoting.Error.unexpected('getDaemonVersion')); + throw remoting.Error.unexpected('getDaemonVersion'); } else { - onDone(that.daemonVersion); + return that.daemonVersion; } }); }; /** - * @param {function(boolean, boolean, boolean):void} onDone - * @param {function(!remoting.Error):void} onError - * @return {void} + * @return {!Promise<remoting.UsageStatsConsent>} */ -remoting.MockHostDaemonFacade.prototype.getUsageStatsConsent = - function(onDone, onError) { +remoting.MockHostDaemonFacade.prototype.getUsageStatsConsent = function() { var that = this; - Promise.resolve().then(function() { + return Promise.resolve().then(function() { if (that.consentSupported === null || that.consentAllowed === null || that.consentSetByPolicy === null) { - onError(remoting.Error.unexpected('getUsageStatsConsent')); + throw remoting.Error.unexpected('getUsageStatsConsent'); } else { - onDone( - that.consentSupported, - that.consentAllowed, - that.consentSetByPolicy); + return { + supported: that.consentSupported, + allowed: that.consentAllowed, + setByPolicy: that.consentSetByPolicy + }; } }); }; @@ -234,140 +216,127 @@ /** * @param {Object} config * @param {boolean} consent Consent to report crash dumps. - * @param {function(remoting.HostController.AsyncResult):void} onDone - * @param {function(!remoting.Error):void} onError - * @return {void} + * @return {!Promise<remoting.HostController.AsyncResult>} */ remoting.MockHostDaemonFacade.prototype.startDaemon = - function(config, consent, onDone, onError) { + function(config, consent) { var that = this; - Promise.resolve().then(function() { + return Promise.resolve().then(function() { if (that.startDaemonResult === null) { - onError(remoting.Error.unexpected('startDaemon')); + throw remoting.Error.unexpected('startDaemon'); } else { - onDone(that.startDaemonResult); + return that.startDaemonResult; } }); }; /** - * @param {function(remoting.HostController.AsyncResult):void} onDone - * @param {function(!remoting.Error):void} onError - * @return {void} + * @return {!Promise<remoting.HostController.AsyncResult>} */ remoting.MockHostDaemonFacade.prototype.stopDaemon = - function(onDone, onError) { + function() { var that = this; - Promise.resolve().then(function() { + return Promise.resolve().then(function() { if (that.stopDaemonResult === null) { - onError(remoting.Error.unexpected('stopDaemon')); + throw remoting.Error.unexpected('stopDaemon'); } else { - onDone(that.stopDaemonResult); + return that.stopDaemonResult; } }); }; /** - * @param {function(remoting.HostController.State):void} onDone - * @param {function(!remoting.Error):void} onError - * @return {void} + * @return {!Promise<remoting.HostController.State>} */ remoting.MockHostDaemonFacade.prototype.getDaemonState = - function(onDone, onError) { + function() { var that = this; - Promise.resolve().then(function() { + return Promise.resolve().then(function() { if (that.daemonState === null) { - onError(remoting.Error.unexpected('getDaemonState')); + throw remoting.Error.unexpected('getDaemonState'); } else { - onDone(that.daemonState); + return that.daemonState; } }); }; /** - * @param {function(Array<remoting.PairedClient>):void} onDone - * @param {function(!remoting.Error):void} onError + * @return {!Promise<Array<remoting.PairedClient>>} */ remoting.MockHostDaemonFacade.prototype.getPairedClients = - function(onDone, onError) { + function() { var that = this; - Promise.resolve().then(function() { + return Promise.resolve().then(function() { if (that.pairedClients === null) { - onError(remoting.Error.unexpected('getPairedClients')); + throw remoting.Error.unexpected('getPairedClients'); } else { - onDone(that.pairedClients); + return that.pairedClients; } }); }; /** - * @param {function(boolean):void} onDone - * @param {function(!remoting.Error):void} onError + * @return {!Promise<boolean>} */ -remoting.MockHostDaemonFacade.prototype.clearPairedClients = - function(onDone, onError) { +remoting.MockHostDaemonFacade.prototype.clearPairedClients = function() { var that = this; - Promise.resolve().then(function() { + return Promise.resolve().then(function() { if (that.pairedClients === null) { - onError(remoting.Error.unexpected('clearPairedClients')); + throw remoting.Error.unexpected('clearPairedClients'); } else { that.pairedClients = []; - onDone(true); + return true; // TODO(jrw): Not always correct. } }); }; /** * @param {string} client - * @param {function(boolean):void} onDone - * @param {function(!remoting.Error):void} onError + * @return {!Promise<boolean>} */ -remoting.MockHostDaemonFacade.prototype.deletePairedClient = - function(client, onDone, onError) { +remoting.MockHostDaemonFacade.prototype.deletePairedClient = function(client) { var that = this; - Promise.resolve().then(function() { + return Promise.resolve().then(function() { if (that.pairedClients === null) { - onError(remoting.Error.unexpected('deletePairedClient')); + throw remoting.Error.unexpected('deletePairedClient'); } else { - that.pairedClients = that.pairedClients.filter(function(/** Object */ c) { + that.pairedClients = that.pairedClients.filter(function(c) { return c['clientId'] != client; }); - onDone(true); + return true; // TODO(jrw): Not always correct. } }); }; /** - * @param {function(string):void} onDone - * @param {function(!remoting.Error):void} onError - * @return {void} + * @return {!Promise<string>} */ -remoting.MockHostDaemonFacade.prototype.getHostClientId = - function(onDone, onError) { +remoting.MockHostDaemonFacade.prototype.getHostClientId = function() { var that = this; - Promise.resolve().then(function() { + return Promise.resolve().then(function() { if (that.hostClientId === null) { - onError(remoting.Error.unexpected('getHostClientId')); + throw remoting.Error.unexpected('getHostClientId'); } else { - onDone(that.hostClientId); + return that.hostClientId; } }); }; /** * @param {string} authorizationCode - * @param {function(string, string):void} onDone - * @param {function(!remoting.Error):void} onError - * @return {void} + * @return {!Promise<{userEmail:string, refreshToken:string}>} */ remoting.MockHostDaemonFacade.prototype.getCredentialsFromAuthCode = - function(authorizationCode, onDone, onError) { + function(authorizationCode) { var that = this; - Promise.resolve().then(function() { + return Promise.resolve().then(function() { if (that.userEmail === null || that.refreshToken === null) { - onError(remoting.Error.unexpected('getCredentialsFromAuthCode')); + throw remoting.Error.unexpected('getCredentialsFromAuthCode'); } else { - onDone(that.userEmail, that.refreshToken); + return { + userEmail: that.userEmail, + refreshToken: that.refreshToken + }; } }); };
diff --git a/remoting/webapp/crd/js/session_connector.js b/remoting/webapp/crd/js/session_connector.js index 7094c43..4481f5c 100644 --- a/remoting/webapp/crd/js/session_connector.js +++ b/remoting/webapp/crd/js/session_connector.js
@@ -31,12 +31,6 @@ remoting.SessionConnector.prototype.connect = function(mode, host, credentialsProvider, opt_suppressOfflineError) {}; - -/** - * Closes the session and removes the plugin element. - */ -remoting.SessionConnector.prototype.closeSession = function() {}; - /** * @interface */ @@ -44,18 +38,13 @@ /** * @param {HTMLElement} clientContainer Container element for the client view. - * @param {function(remoting.ConnectionInfo):void} onConnected Callback on - * success. - * @param {function(!remoting.Error):void} onError Callback on error. - * @param {function(!remoting.Error):void} onConnectionFailed Callback for when - * the connection fails. * @param {Array<string>} requiredCapabilities Connector capabilities * required by this application. + * @param {remoting.ClientSession.EventHandler} handler * @return {remoting.SessionConnector} */ remoting.SessionConnectorFactory.prototype.createConnector = - function(clientContainer, onConnected, onError, - onConnectionFailed, requiredCapabilities) {}; + function(clientContainer, requiredCapabilities, handler) {}; /** * @type {remoting.SessionConnectorFactory}
diff --git a/remoting/webapp/crd/js/session_connector_impl.js b/remoting/webapp/crd/js/session_connector_impl.js index 6bad8b3..6c197890 100644 --- a/remoting/webapp/crd/js/session_connector_impl.js +++ b/remoting/webapp/crd/js/session_connector_impl.js
@@ -21,41 +21,36 @@ /** * @param {HTMLElement} clientContainer Container element for the client view. - * @param {function(remoting.ConnectionInfo):void} onConnected Callback on - * success. - * @param {function(!remoting.Error):void} onError Callback on error. - * @param {function(!remoting.Error):void} onConnectionFailed Callback for when - * the connection fails. * @param {Array<string>} requiredCapabilities Connector capabilities * required by this application. + * @param {remoting.ClientSession.EventHandler} handler * @constructor * @implements {remoting.SessionConnector} */ -remoting.SessionConnectorImpl = function(clientContainer, onConnected, onError, - onConnectionFailed, - requiredCapabilities) { +remoting.SessionConnectorImpl = + function(clientContainer, requiredCapabilities, handler) { /** @private {HTMLElement} */ this.clientContainer_ = clientContainer; - /** @private {function(remoting.ConnectionInfo):void} */ - this.onConnected_ = onConnected; - - /** @private {function(!remoting.Error):void} */ - this.onError_ = onError; - - /** @private {function(!remoting.Error):void} */ - this.onConnectionFailed_ = onConnectionFailed; - - /** @private {Array<string>} */ - this.requiredCapabilities_ = requiredCapabilities; + /** @private */ + this.onError_ = handler.onError.bind(handler); /** @private */ - this.bound_ = { - onStateChange : this.onStateChange_.bind(this) - }; + this.handler_ = handler; + + /** @private {Array<string>} */ + this.requiredCapabilities_ = [ + remoting.ClientSession.Capability.SEND_INITIAL_RESOLUTION, + remoting.ClientSession.Capability.RATE_LIMIT_RESIZE_REQUESTS, + remoting.ClientSession.Capability.VIDEO_RECORDER + ]; + + // Append the app-specific capabilities. + this.requiredCapabilities_.push.apply(this.requiredCapabilities_, + requiredCapabilities); // Initialize/declare per-connection state. - this.closeSession(); + this.closeSession_(); }; /** @@ -63,10 +58,14 @@ * second connection. Note the none of the shared WCS state is reset. * @private */ -remoting.SessionConnectorImpl.prototype.closeSession = function() { +remoting.SessionConnectorImpl.prototype.closeSession_ = function() { // It's OK to initialize these member variables here because the // constructor calls this method. + base.dispose(this.eventHook_); + /** @private {base.Disposable} */ + this.eventHook_ = null; + /** @private {remoting.Host} */ this.host_ = null; @@ -106,7 +105,7 @@ // in a new clientJid and a new callback. In this case, cancel any existing // connect operation and remove the old client plugin before instantiating a // new one. - this.closeSession(); + this.closeSession_(); remoting.app.setConnectionMode(mode); this.host_ = host; this.credentialsProvider_ = credentialsProvider; @@ -213,10 +212,8 @@ remoting.clientSession = this.clientSession_; this.clientSession_.logHostOfflineErrors(this.logHostOfflineErrors_); - this.clientSession_.addEventListener( - remoting.ClientSession.Events.stateChanged, - this.bound_.onStateChange); - + this.eventHook_ = new base.EventHook( + this.clientSession_, 'stateChanged', this.onStateChange_.bind(this)); this.plugin_.connect( this.host_, this.signalStrategy_.getJid(), this.credentialsProvider_); }; @@ -227,15 +224,11 @@ */ remoting.SessionConnectorImpl.prototype.pluginError_ = function(error) { this.signalStrategy_.setIncomingStanzaCallback(null); - this.clientSession_.disconnect(error); - this.closeSession(); + this.closeSession_(); }; /** - * Handle a change in the state of the client session prior to successful - * connection (after connection, this class no longer handles state change - * events). Errors that occur while connecting either trigger a reconnect - * or notify the onError handler. + * Handle a change in the state of the client session. * * @param {remoting.ClientSession.StateEvent=} event * @return {void} Nothing. @@ -244,25 +237,16 @@ remoting.SessionConnectorImpl.prototype.onStateChange_ = function(event) { switch (event.current) { case remoting.ClientSession.State.CONNECTED: - // When the connection succeeds, deregister for state-change callbacks - // and pass the session to the onConnected callback. It is expected that - // it will register a new state-change callback to handle disconnect - // or error conditions. - this.clientSession_.removeEventListener( - remoting.ClientSession.Events.stateChanged, - this.bound_.onStateChange); - var connectionInfo = new remoting.ConnectionInfo( this.host_, this.credentialsProvider_, this.clientSession_, this.plugin_); - this.onConnected_(connectionInfo); + this.handler_.onConnected(connectionInfo); break; case remoting.ClientSession.State.CONNECTING: - remoting.identity.getEmail().then( - function(/** string */ email) { - console.log('Connecting as ' + email); - }); + remoting.identity.getEmail().then(function(/** string */ email) { + console.log('Connecting as ' + email); + }); break; case remoting.ClientSession.State.AUTHENTICATED: @@ -274,24 +258,14 @@ break; case remoting.ClientSession.State.CLOSED: - // This class deregisters for state-change callbacks when the CONNECTED - // state is reached, so it only sees the CLOSED state in exceptional - // circumstances. For example, a CONNECTING -> CLOSED transition happens - // if the host closes the connection without an error message instead of - // accepting it. Since there's no way of knowing exactly what went wrong, - // we rely on server-side logs in this case and report a generic error - // message. - this.onError_(remoting.Error.unexpected()); + this.handler_.onDisconnected(); break; case remoting.ClientSession.State.FAILED: var error = this.clientSession_.getError(); console.error('Client plugin reported connection failed: ' + error.toString()); - if (error == null) { - error = remoting.Error.unexpected(); - } - this.onConnectionFailed_(error); + this.handler_.onConnectionFailed(error || remoting.Error.unexpected()); break; default: @@ -300,6 +274,10 @@ // sync, and even then the version check should ensure compatibility. this.onError_(new remoting.Error(remoting.Error.Tag.MISSING_PLUGIN)); } + + if (this.clientSession_.isFinished()) { + this.closeSession_(); + } }; /** @@ -310,20 +288,13 @@ /** * @param {HTMLElement} clientContainer Container element for the client view. - * @param {function(remoting.ConnectionInfo):void} onConnected Callback on - * success. - * @param {function(!remoting.Error):void} onError Callback on error. - * @param {function(!remoting.Error):void} onConnectionFailed Callback for when - * the connection fails. * @param {Array<string>} requiredCapabilities Connector capabilities * required by this application. + * @param {remoting.ClientSession.EventHandler} handler * @return {remoting.SessionConnector} */ remoting.DefaultSessionConnectorFactory.prototype.createConnector = - function(clientContainer, onConnected, onError, - onConnectionFailed, requiredCapabilities) { - return new remoting.SessionConnectorImpl(clientContainer, onConnected, - onError, - onConnectionFailed, - requiredCapabilities); + function(clientContainer, requiredCapabilities, handler) { + return new remoting.SessionConnectorImpl(clientContainer, + requiredCapabilities, handler); };
diff --git a/sandbox/linux/BUILD.gn b/sandbox/linux/BUILD.gn index 1794199..21f856b 100644 --- a/sandbox/linux/BUILD.gn +++ b/sandbox/linux/BUILD.gn
@@ -290,11 +290,11 @@ sources = [ "system_headers/android_arm64_ucontext.h", "system_headers/android_arm_ucontext.h", - "system_headers/android_futex.h", "system_headers/android_i386_ucontext.h", "system_headers/android_ucontext.h", "system_headers/arm64_linux_syscalls.h", "system_headers/arm_linux_syscalls.h", + "system_headers/linux_futex.h", "system_headers/linux_seccomp.h", "system_headers/linux_syscalls.h", "system_headers/x86_32_linux_syscalls.h",
diff --git a/sandbox/linux/sandbox_linux.gypi b/sandbox/linux/sandbox_linux.gypi index 4305b41..1cf3b2d 100644 --- a/sandbox/linux/sandbox_linux.gypi +++ b/sandbox/linux/sandbox_linux.gypi
@@ -280,13 +280,13 @@ 'sources': [ 'system_headers/android_arm64_ucontext.h', 'system_headers/android_arm_ucontext.h', - 'system_headers/android_futex.h', 'system_headers/android_i386_ucontext.h', 'system_headers/android_mips_ucontext.h', 'system_headers/android_ucontext.h', 'system_headers/arm64_linux_syscalls.h', 'system_headers/arm_linux_syscalls.h', 'system_headers/capability.h', + 'system_headers/linux_futex.h', 'system_headers/linux_seccomp.h', 'system_headers/linux_syscalls.h', 'system_headers/mips_linux_syscalls.h',
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc index e6e89349..614849f 100644 --- a/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc +++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
@@ -6,7 +6,6 @@ #include <errno.h> #include <fcntl.h> -#include <linux/futex.h> #include <sched.h> #include <signal.h> #include <string.h> @@ -32,7 +31,7 @@ #include "sandbox/linux/seccomp-bpf/syscall.h" #include "sandbox/linux/services/syscall_wrappers.h" #include "sandbox/linux/services/thread_helpers.h" -#include "sandbox/linux/system_headers/android_futex.h" +#include "sandbox/linux/system_headers/linux_futex.h" #include "sandbox/linux/system_headers/linux_syscalls.h" #include "sandbox/linux/tests/test_utils.h" #include "sandbox/linux/tests/unit_tests.h"
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc index b315f12a..282e727 100644 --- a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc +++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
@@ -7,7 +7,6 @@ #include <errno.h> #include <fcntl.h> #include <fcntl.h> -#include <linux/futex.h> #include <linux/net.h> #include <sched.h> #include <signal.h> @@ -30,12 +29,11 @@ #include "sandbox/linux/bpf_dsl/seccomp_macros.h" #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" +#include "sandbox/linux/system_headers/linux_futex.h" #include "sandbox/linux/system_headers/linux_syscalls.h" #if defined(OS_ANDROID) -#include "sandbox/linux/system_headers/android_futex.h" - #if !defined(F_DUPFD_CLOEXEC) #define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6) #endif
diff --git a/sandbox/linux/system_headers/android_futex.h b/sandbox/linux/system_headers/linux_futex.h similarity index 88% rename from sandbox/linux/system_headers/android_futex.h rename to sandbox/linux/system_headers/linux_futex.h index 11b766f4..91733a8d 100644 --- a/sandbox/linux/system_headers/android_futex.h +++ b/sandbox/linux/system_headers/linux_futex.h
@@ -2,8 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_ANDROID_FUTEX_H_ -#define SANDBOX_LINUX_SYSTEM_HEADERS_ANDROID_FUTEX_H_ +#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FUTEX_H_ +#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FUTEX_H_ + +#include <linux/futex.h> #if !defined(FUTEX_WAIT) #define FUTEX_WAIT 0 @@ -77,4 +79,4 @@ #define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG) #endif -#endif // SANDBOX_LINUX_SYSTEM_HEADERS_ANDROID_FUTEX_H_ +#endif // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FUTEX_H_
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json index 539bbd84..604cc25 100644 --- a/testing/buildbot/chromium.chromiumos.json +++ b/testing/buildbot/chromium.chromiumos.json
@@ -1,4 +1,14 @@ { + "Linux ChromiumOS GN": { + "additional_compile_targets": [ + "all" + ], + "gtest_tests": [ + { + "test": "base_unittests" + } + ] + }, "Linux ChromiumOS Ozone Tests (1)": { "gtest_tests": [ {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index a91be73..b0903de4 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -4,14 +4,14 @@ { "args": [ "--enable-browser-side-navigation", - "--gtest_filter=-BatteryMonitorImplTest.BatteryManagerDefaultValues:BatteryMonitorImplTest.BatteryManagerResolvePromise:BatteryMonitorImplTest.BatteryManagerWithEventListener:BookmarkletTest.DocumentWrite:BookmarkletTest.NonEmptyResult:BookmarkletTest.Redirect:BookmarkletTest.RedirectVoided:ChildProcessLauncherBrowserTest.ChildSpawnFail:CrossProcessFrameTreeBrowserTest.CreateCrossProcessSubframeProxies:CrossProcessFrameTreeBrowserTest.OriginSetOnCrossProcessNavigations:CrossSiteRedirectorBrowserTest.VerifyCrossSiteRedirectURL:CrossSiteTransferTest.NoLeakOnCrossSiteCancel:CrossSiteTransferTest.ReplaceEntryCrossProcessThenTransfer:CrossSiteTransferTest.ReplaceEntryCrossProcessTwice:CrossSiteTransferTest.ReplaceEntryInProcessThenTranfers:DatabaseTest.ReloadPage:DeviceInertialSensorBrowserTest.LightOneOffInfintyTest:DeviceInertialSensorBrowserTest.LightTest:DeviceInertialSensorBrowserTest.MotionNullTest:DeviceInertialSensorBrowserTest.MotionTest:DeviceInertialSensorBrowserTest.OrientationNullTest:DeviceInertialSensorBrowserTest.OrientationTest:DomSerializerTests.SerializeDocumentWithDownloadedIFrame:DOMStorageBrowserTest.SanityCheck:DOMStorageBrowserTest.SanityCheckIncognito:DownloadContentTest.CancelAtFinalRename:DownloadContentTest.CancelAtRelease:DownloadContentTest.CancelInterruptedDownload:DownloadContentTest.CancelResumingDownload:DownloadContentTest.DownloadCancelled:DownloadContentTest.DownloadGZipWithNoContent:DownloadContentTest.DownloadOctetStream:DownloadContentTest.MultiDownload:DownloadContentTest.RemoveDownload:DownloadContentTest.RemoveResumingDownload:DownloadContentTest.ResumeInterruptedDownload:DownloadContentTest.ResumeInterruptedDownloadBadPrecondition:DownloadContentTest.ResumeInterruptedDownloadNoRange:DownloadContentTest.ResumeInterruptedDownloadNoVerifiers:DownloadContentTest.ResumeWithDeletedFile:DownloadContentTest.ResumeWithFileFinalRenameError:DownloadContentTest.ResumeWithFileInitError:DownloadContentTest.ResumeWithFileIntermediateRenameError:DownloadContentTest.ShutdownAtRelease:DownloadContentTest.ShutdownInProgress:File/MediaTest.VideoBearOpusOgg/0:File/MediaTest.VideoBearOpusWebm/0:File/MediaTest.VideoBearSilentTheora/0:File/MediaTest.VideoBearSilentWebm/0:File/MediaTest.VideoBearTheora/0:File/MediaTest.VideoBearWavAlaw/0:File/MediaTest.VideoBearWavMulaw/0:File/MediaTest.VideoBearWavPcm/0:File/MediaTest.VideoBearWavPcm192kHz/0:File/MediaTest.VideoBearWavPcm3kHz/0:File/MediaTest.VideoBearWebm/0:File/MediaTest.VideoTulipWebm/0:FileSystemBrowserTest.CreateTest:FileSystemBrowserTest.RequestTest:FileSystemBrowserTestWithLowQuota.QuotaTest:FrameTreeBrowserTest.FrameTreeAfterCrash:FrameTreeBrowserTest.SandboxFlagsSetForChildFrames:GinBrowserTest.GinAndGarbageCollection:HostZoomMapImplBrowserTest.GetZoomForView_Host:HostZoomMapImplBrowserTest.GetZoomForView_HostAndScheme:IndexedDBBrowserTest.BlobsCountAgainstQuota:IndexedDBBrowserTest.CallbackAccounting:IndexedDBBrowserTest.CanDeleteWhenOverQuotaTest:IndexedDBBrowserTest.ConnectionsClosedOnTabClose:IndexedDBBrowserTest.CursorPrefetch:IndexedDBBrowserTest.CursorTest:IndexedDBBrowserTest.CursorTestIncognito:IndexedDBBrowserTest.DatabaseTest:IndexedDBBrowserTest.DeleteCompactsBackingStore:IndexedDBBrowserTest.DeleteForOriginDeletesBlobs:IndexedDBBrowserTest.DiskFullOnCommit:IndexedDBBrowserTest.DoesntHangTest:IndexedDBBrowserTest.EmptyBlob:IndexedDBBrowserTest.ForceCloseEventTest:IndexedDBBrowserTest.IndexTest:IndexedDBBrowserTest.KeyPathTest:IndexedDBBrowserTest.KeyTypesTest:IndexedDBBrowserTest.LevelDBLogFileTest:IndexedDBBrowserTest.NullKeyPathPersistence:IndexedDBBrowserTest.ObjectStoreTest:IndexedDBBrowserTest.PRE_NullKeyPathPersistence:IndexedDBBrowserTest.PRE_PRE_VersionChangeCrashResilience:IndexedDBBrowserTest.PRE_VersionChangeCrashResilience:IndexedDBBrowserTest.TransactionGetTest:IndexedDBBrowserTest.TransactionTest:IndexedDBBrowserTest.VersionChangeCrashResilience:IndexedDBBrowserTestSingleProcess.RenderThreadShutdownTest:IndexedDBBrowserTestWithCorruptLevelDB.DestroyTest:IndexedDBBrowserTestWithGCExposed.BlobDidAck:IndexedDBBrowserTestWithGCExposed.BlobDidAckPrefetch:IndexedDBBrowserTestWithGCExposed.DatabaseCallbacksTest:IndexedDBBrowserTestWithLowQuota.QuotaTest:IndexedDBBrowserTestWithMissingSSTFile.DestroyTest:IndexedDBBrowserTestWithVersion0Schema.MigrationTest:IndexedDBBrowserTestWithVersion123456Schema.DestroyTest:IndexedDBBrowserTestWithVersion987654SSVData.DestroyTest:ManifestBrowserTest.DummyManifest:ManifestBrowserTest.DynamicManifest:ManifestBrowserTest.ParseErrorManifest:ManifestBrowserTest.ParsingErrorsManifest:MediaCanPlayTypeTest.CodecSupportTest_Avc1Variants:MediaCanPlayTypeTest.CodecSupportTest_Avc3Variants:MediaCanPlayTypeTest.CodecSupportTest_AvcLevels:MediaCanPlayTypeTest.CodecSupportTest_HLS:MediaCanPlayTypeTest.CodecSupportTest_mp3:MediaCanPlayTypeTest.CodecSupportTest_mp4:MediaCanPlayTypeTest.CodecSupportTest_Mp4aVariants:MediaCanPlayTypeTest.CodecSupportTest_ogg:MediaCanPlayTypeTest.CodecSupportTest_wav:MediaCanPlayTypeTest.CodecSupportTest_webm:MediaTest.Navigate:NavigationControllerBrowserTest.CorrectLengthWithCurrentItemReplacement:NavigationControllerBrowserTest.CorrectLengthWithNewTabNavigatingFromWebUI:NavigationControllerBrowserTest.DontIgnoreBackAfterNavEntryLimit:NavigationControllerBrowserTest.NavigationTypeClassification_ClientSideRedirect:NavigationControllerBrowserTest.NavigationTypeClassification_ExistingPage:NavigationControllerBrowserTest.NavigationTypeClassification_InPage:NavigationControllerBrowserTest.NavigationTypeClassification_NewAndAutoSubframe:NavigationControllerBrowserTest.NavigationTypeClassification_NewPage:NavigationControllerBrowserTest.SubframeOnEmptyPage:OutOfProcessPPAPITest.InputEvent:OutOfProcessPPAPITest.MediaStreamAudioTrack:OutOfProcessPPAPITest.MediaStreamVideoTrack:PluginPowerSaverHelperTest.ClearWhitelistOnNavigate:RendererAccessibilityTest.AccessibilityMessagesQueueWhileSwappedOut:RendererAccessibilityTest.DetachAccessibilityObject:RendererAccessibilityTest.EventOnObjectNotInTree:RendererAccessibilityTest.HideAccessibilityObject:RendererAccessibilityTest.SendFullAccessibilityTreeOnReload:RendererAccessibilityTest.ShowAccessibilityObject:RenderFrameHostImplBrowserTest.IsFocused_AtLoad:RenderFrameHostImplBrowserTest.IsFocused_Widget:RenderFrameHostManagerTest.BackForwardNotStale:RenderFrameHostManagerTest.ClickLinkAfter204Error:RenderFrameHostManagerTest.DisownSubframeOpener:RenderFrameHostManagerTest.DontPreemptNavigationWithFrameTreeUpdate:RenderFrameHostManagerTest.ForceSwapAfterWebUIBindings:RenderFrameHostManagerTest.IgnoreRendererDebugURLsWhenCrashed:RenderFrameHostManagerTest.NoScriptAccessAfterSwapOut:RenderFrameHostManagerTest.RendererDebugURLsDontSwap:RenderFrameHostManagerTest.RestoreFileAccessForHistoryNavigation:RenderFrameHostManagerTest.RestoreSubframeFileAccessForHistoryNavigation:RenderFrameHostManagerTest.ShowLoadingURLUntilSpoof:RenderFrameImplTest.FrameResize:RenderFrameImplTest.FrameWasShown:RenderFrameImplTest.SubframeWidget:RenderProcessHostTest.AllProcessExitedCallsBeforeAnyHostDestroyedCalls:RenderViewBrowserTest.ConfirmCacheInformationPlumbed:RenderViewImplTest.ContextMenu:RenderViewImplTest.DecideNavigationPolicy:RenderViewImplTest.DidFailProvisionalLoadWithErrorForCancellation:RenderViewImplTest.FocusElementCallsFocusedNodeChanged:RenderViewImplTest.GetCompositionCharacterBoundsTest:RenderViewImplTest.GetSSLStatusOfFrame:RenderViewImplTest.ImeComposition:RenderViewImplTest.InsertCharacters:RenderViewImplTest.MessageOrderInDidChangeSelection:RenderViewImplTest.NavigateFrame:RenderViewImplTest.OnExtendSelectionAndDelete:RenderViewImplTest.OnHandleKeyboardEvent:RenderViewImplTest.OnImeTypeChanged:RenderViewImplTest.OnNavigationHttpPost:RenderViewImplTest.OnSetTextDirection:RenderViewImplTest.PreferredSizeZoomed:RenderViewImplTest.ReloadWhileSwappedOut:RenderViewImplTest.ScreenMetricsEmulation:RenderViewImplTest.SendCandidateWindowEvents:RenderViewImplTest.SendFaviconURLUpdateEvent:RenderViewImplTest.SendSwapOutACK:RenderViewImplTest.ServiceWorkerNetworkProviderSetup:RenderViewImplTest.SetEditableSelectionAndComposition:RenderViewImplTest.StaleNavigationsIgnored:RenderViewImplTest.TestBackForward:RenderViewImplTest.ZoomLimit:ResourceDispatcherHostBrowserTest.CrossSiteAfterCrash:ResourceDispatcherHostBrowserTest.CrossSiteFailedRequest:ResourceDispatcherHostBrowserTest.CrossSiteNavigationErrorPage2:ResourceDispatcherHostBrowserTest.CrossSiteNoUnloadOn204:ResourceFetcherTests.ResourceFetcher404:ResourceFetcherTests.ResourceFetcherDeletedInCallback:ResourceFetcherTests.ResourceFetcherDidFail:ResourceFetcherTests.ResourceFetcherDownload:ResourceFetcherTests.ResourceFetcherPost:ResourceFetcherTests.ResourceFetcherSetHeader:ResourceFetcherTests.ResourceFetcherTimeout:SecurityExploitBrowserTest.AttemptDuplicateRenderViewHost:SecurityExploitBrowserTest.AttemptDuplicateRenderWidgetHost:SecurityExploitBrowserTest.InterstitialCommandFromUnderlyingContent:ServiceWorkerBrowserTest.CrossSiteTransfer:ServiceWorkerBrowserTest.ImportsBustMemcache:ServiceWorkerBrowserTest.Reload:ServiceWorkerBrowserTest.ResponseFromHTTPServiceWorkerIsNotMarkedAsSecure:ServiceWorkerBrowserTest.ResponseFromHTTPSServiceWorkerIsMarkedAsSecure:SessionHistoryTest.BasicBackForward:SessionHistoryTest.CrossFrameFormBackForward:SessionHistoryTest.FragmentBackForward:SessionHistoryTest.FrameBackForward:SessionHistoryTest.FrameFormBackForward:SessionHistoryTest.HistoryLength:SessionHistoryTest.JavascriptHistory:SessionHistoryTest.LocationChangeInSubframe:SessionHistoryTest.LocationReplace:SitePerProcessAccessibilityBrowserTest.CrossSiteIframeAccessibility:SitePerProcessBrowserTest.CompositorFrameSwapped:SitePerProcessBrowserTest.CreateProxiesForNewFrames:SitePerProcessBrowserTest.CrossSiteDidStopLoading:SitePerProcessBrowserTest.CrossSiteIframe:SitePerProcessBrowserTest.DynamicSandboxFlags:SitePerProcessBrowserTest.DynamicSandboxFlagsRemoteToLocal:SitePerProcessBrowserTest.KillingRendererClearsDescendantProxies:SitePerProcessBrowserTest.NavigateRemoteFrame:SitePerProcessBrowserTest.NavigateRemoteFrameToBlankAndDataURLs:SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcess:SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcessWithSubtree:SitePerProcessBrowserTest.NavigateWithSiblingRemoteFrame:SitePerProcessBrowserTest.OriginReplication:SitePerProcessBrowserTest.ProxyCreationSkipsSubtree:SitePerProcessBrowserTest.SandboxFlagsReplication:SitePerProcessDevToolsBrowserTest.CrossSiteIframeAgentHost:SpeechRecognitionBrowserTest.OneShotRecognition:StatsTableBrowserTest.StartWithStatTable:SuppressErrorPageTest.DoesNotSuppress:SuppressErrorPageTest.Suppresses:TracingControllerTest.EnableAndDisableRecording:TracingControllerTest.EnableAndDisableRecordingWithEmptyFileAndNullCallback:TracingControllerTest.EnableAndDisableRecordingWithFilePath:TracingControllerTest.EnableCaptureAndDisableMonitoring:TracingControllerTest.EnableCaptureAndDisableMonitoringWithEmptyFileAndNullCallback:TracingControllerTest.EnableCaptureAndDisableMonitoringWithFilePath:TracingControllerTest.GetCategories:TransitionBrowserTest.NormalNavigationNotDeferred:TransitionBrowserTest.TransitionNavigationDataIsCleared:TransitionBrowserTest.TransitionNavigationIsDeferred:WebContentsImplBrowserTest.ClearNonVisiblePendingOnFail:WebContentsImplBrowserTest.GetSizeForNewRenderView:WebContentsViewAuraTest.ScreenshotForSwappedOutRenderViews:WebRtcAecDumpBrowserTest.CallWithAecDump:WebRtcAecDumpBrowserTest.CallWithAecDumpEnabledThenDisabled:WebRtcAecDumpBrowserTest.TwoCallsWithAecDump:WebUIMojoTest.EndToEndPing:WorkerTest.IncognitoSharedWorkers:WorkerTest.MultipleSharedWorkers:WorkerTest.MultipleWorkers:WorkerTest.PassMessagePortToSharedWorker:WorkerTest.PassMessagePortToSharedWorkerDontWaitForConnect:WorkerTest.SharedWorkerTlsClientAuth:WorkerTest.SingleSharedWorker:WorkerTest.SingleWorker:WorkerTest.WorkerTlsClientAuth" + "--gtest_filter=-BatteryMonitorImplTest.BatteryManagerDefaultValues:BatteryMonitorImplTest.BatteryManagerResolvePromise:BatteryMonitorImplTest.BatteryManagerWithEventListener:BookmarkletTest.DocumentWrite:BookmarkletTest.NonEmptyResult:BookmarkletTest.Redirect:BookmarkletTest.RedirectVoided:ChildProcessLauncherBrowserTest.ChildSpawnFail:CrossProcessFrameTreeBrowserTest.CreateCrossProcessSubframeProxies:CrossProcessFrameTreeBrowserTest.OriginSetOnCrossProcessNavigations:CrossSiteRedirectorBrowserTest.VerifyCrossSiteRedirectURL:CrossSiteTransferTest.NoLeakOnCrossSiteCancel:CrossSiteTransferTest.ReplaceEntryCrossProcessThenTransfer:CrossSiteTransferTest.ReplaceEntryCrossProcessTwice:CrossSiteTransferTest.ReplaceEntryInProcessThenTranfers:DatabaseTest.ReloadPage:DeviceInertialSensorBrowserTest.LightOneOffInfintyTest:DeviceInertialSensorBrowserTest.LightTest:DeviceInertialSensorBrowserTest.MotionNullTest:DeviceInertialSensorBrowserTest.MotionTest:DeviceInertialSensorBrowserTest.OrientationNullTest:DeviceInertialSensorBrowserTest.OrientationTest:DomSerializerTests.SerializeDocumentWithDownloadedIFrame:DOMStorageBrowserTest.SanityCheck:DOMStorageBrowserTest.SanityCheckIncognito:DownloadContentTest.CancelAtFinalRename:DownloadContentTest.CancelAtRelease:DownloadContentTest.CancelInterruptedDownload:DownloadContentTest.CancelResumingDownload:DownloadContentTest.DownloadCancelled:DownloadContentTest.DownloadGZipWithNoContent:DownloadContentTest.DownloadOctetStream:DownloadContentTest.MultiDownload:DownloadContentTest.RemoveDownload:DownloadContentTest.RemoveResumingDownload:DownloadContentTest.ResumeInterruptedDownload:DownloadContentTest.ResumeInterruptedDownloadBadPrecondition:DownloadContentTest.ResumeInterruptedDownloadNoRange:DownloadContentTest.ResumeInterruptedDownloadNoVerifiers:DownloadContentTest.ResumeWithDeletedFile:DownloadContentTest.ResumeWithFileFinalRenameError:DownloadContentTest.ResumeWithFileInitError:DownloadContentTest.ResumeWithFileIntermediateRenameError:DownloadContentTest.ShutdownAtRelease:DownloadContentTest.ShutdownInProgress:File/MediaTest.VideoBearOpusOgg/0:File/MediaTest.VideoBearOpusWebm/0:File/MediaTest.VideoBearSilentTheora/0:File/MediaTest.VideoBearSilentWebm/0:File/MediaTest.VideoBearTheora/0:File/MediaTest.VideoBearWavAlaw/0:File/MediaTest.VideoBearWavMulaw/0:File/MediaTest.VideoBearWavPcm/0:File/MediaTest.VideoBearWavPcm192kHz/0:File/MediaTest.VideoBearWavPcm3kHz/0:File/MediaTest.VideoBearWebm/0:File/MediaTest.VideoTulipWebm/0:FileSystemBrowserTest.CreateTest:FileSystemBrowserTest.RequestTest:FileSystemBrowserTestWithLowQuota.QuotaTest:FrameTreeBrowserTest.FrameTreeAfterCrash:FrameTreeBrowserTest.SandboxFlagsSetForChildFrames:GinBrowserTest.GinAndGarbageCollection:HostZoomMapImplBrowserTest.GetZoomForView_Host:HostZoomMapImplBrowserTest.GetZoomForView_HostAndScheme:IndexedDBBrowserTest.BlobsCountAgainstQuota:IndexedDBBrowserTest.CallbackAccounting:IndexedDBBrowserTest.CanDeleteWhenOverQuotaTest:IndexedDBBrowserTest.ConnectionsClosedOnTabClose:IndexedDBBrowserTest.CursorPrefetch:IndexedDBBrowserTest.CursorTest:IndexedDBBrowserTest.CursorTestIncognito:IndexedDBBrowserTest.DatabaseTest:IndexedDBBrowserTest.DeleteCompactsBackingStore:IndexedDBBrowserTest.DeleteForOriginDeletesBlobs:IndexedDBBrowserTest.DiskFullOnCommit:IndexedDBBrowserTest.DoesntHangTest:IndexedDBBrowserTest.EmptyBlob:IndexedDBBrowserTest.ForceCloseEventTest:IndexedDBBrowserTest.IndexTest:IndexedDBBrowserTest.KeyPathTest:IndexedDBBrowserTest.KeyTypesTest:IndexedDBBrowserTest.LevelDBLogFileTest:IndexedDBBrowserTest.NullKeyPathPersistence:IndexedDBBrowserTest.ObjectStoreTest:IndexedDBBrowserTest.PRE_NullKeyPathPersistence:IndexedDBBrowserTest.PRE_PRE_VersionChangeCrashResilience:IndexedDBBrowserTest.PRE_VersionChangeCrashResilience:IndexedDBBrowserTest.TransactionGetTest:IndexedDBBrowserTest.TransactionTest:IndexedDBBrowserTest.VersionChangeCrashResilience:IndexedDBBrowserTestSingleProcess.RenderThreadShutdownTest:IndexedDBBrowserTestWithCorruptLevelDB.DestroyTest:IndexedDBBrowserTestWithGCExposed.BlobDidAck:IndexedDBBrowserTestWithGCExposed.BlobDidAckPrefetch:IndexedDBBrowserTestWithGCExposed.DatabaseCallbacksTest:IndexedDBBrowserTestWithLowQuota.QuotaTest:IndexedDBBrowserTestWithMissingSSTFile.DestroyTest:IndexedDBBrowserTestWithVersion0Schema.MigrationTest:IndexedDBBrowserTestWithVersion123456Schema.DestroyTest:IndexedDBBrowserTestWithVersion987654SSVData.DestroyTest:ManifestBrowserTest.DummyManifest:ManifestBrowserTest.DynamicManifest:ManifestBrowserTest.ParseErrorManifest:ManifestBrowserTest.ParsingErrorsManifest:MediaCanPlayTypeTest.CodecSupportTest_Avc1Variants:MediaCanPlayTypeTest.CodecSupportTest_Avc3Variants:MediaCanPlayTypeTest.CodecSupportTest_AvcLevels:MediaCanPlayTypeTest.CodecSupportTest_HLS:MediaCanPlayTypeTest.CodecSupportTest_mp3:MediaCanPlayTypeTest.CodecSupportTest_mp4:MediaCanPlayTypeTest.CodecSupportTest_Mp4aVariants:MediaCanPlayTypeTest.CodecSupportTest_ogg:MediaCanPlayTypeTest.CodecSupportTest_wav:MediaCanPlayTypeTest.CodecSupportTest_webm:MediaTest.Navigate:NavigationControllerBrowserTest.CorrectLengthWithCurrentItemReplacement:NavigationControllerBrowserTest.CorrectLengthWithNewTabNavigatingFromWebUI:NavigationControllerBrowserTest.DontIgnoreBackAfterNavEntryLimit:NavigationControllerBrowserTest.ErrorPageReplacement:NavigationControllerBrowserTest.NavigationTypeClassification_ClientSideRedirect:NavigationControllerBrowserTest.NavigationTypeClassification_ExistingPage:NavigationControllerBrowserTest.NavigationTypeClassification_InPage:NavigationControllerBrowserTest.NavigationTypeClassification_NewAndAutoSubframe:NavigationControllerBrowserTest.NavigationTypeClassification_NewPage:NavigationControllerBrowserTest.SubframeOnEmptyPage:OutOfProcessPPAPITest.InputEvent:OutOfProcessPPAPITest.MediaStreamAudioTrack:OutOfProcessPPAPITest.MediaStreamVideoTrack:PluginPowerSaverHelperTest.ClearWhitelistOnNavigate:RendererAccessibilityTest.AccessibilityMessagesQueueWhileSwappedOut:RendererAccessibilityTest.DetachAccessibilityObject:RendererAccessibilityTest.EventOnObjectNotInTree:RendererAccessibilityTest.HideAccessibilityObject:RendererAccessibilityTest.SendFullAccessibilityTreeOnReload:RendererAccessibilityTest.ShowAccessibilityObject:RenderFrameHostImplBrowserTest.IsFocused_AtLoad:RenderFrameHostImplBrowserTest.IsFocused_Widget:RenderFrameHostManagerTest.BackForwardNotStale:RenderFrameHostManagerTest.ClickLinkAfter204Error:RenderFrameHostManagerTest.DisownSubframeOpener:RenderFrameHostManagerTest.DontPreemptNavigationWithFrameTreeUpdate:RenderFrameHostManagerTest.ForceSwapAfterWebUIBindings:RenderFrameHostManagerTest.IgnoreRendererDebugURLsWhenCrashed:RenderFrameHostManagerTest.NoScriptAccessAfterSwapOut:RenderFrameHostManagerTest.RendererDebugURLsDontSwap:RenderFrameHostManagerTest.RestoreFileAccessForHistoryNavigation:RenderFrameHostManagerTest.RestoreSubframeFileAccessForHistoryNavigation:RenderFrameHostManagerTest.ShowLoadingURLUntilSpoof:RenderProcessHostTest.AllProcessExitedCallsBeforeAnyHostDestroyedCalls:RenderViewBrowserTest.ConfirmCacheInformationPlumbed:RenderViewImplTest.DecideNavigationPolicy:RenderViewImplTest.InsertCharacters:RenderViewImplTest.NavigateFrame:RenderViewImplTest.OnHandleKeyboardEvent:RenderViewImplTest.OnNavigationHttpPost:RenderViewImplTest.ReloadWhileSwappedOut:RenderViewImplTest.StaleNavigationsIgnored:RenderViewImplTest.TestBackForward:ResourceDispatcherHostBrowserTest.CrossSiteAfterCrash:ResourceDispatcherHostBrowserTest.CrossSiteFailedRequest:ResourceDispatcherHostBrowserTest.CrossSiteNavigationErrorPage2:ResourceDispatcherHostBrowserTest.CrossSiteNoUnloadOn204:ResourceFetcherTests.ResourceFetcher404:ResourceFetcherTests.ResourceFetcherDeletedInCallback:ResourceFetcherTests.ResourceFetcherDidFail:ResourceFetcherTests.ResourceFetcherDownload:ResourceFetcherTests.ResourceFetcherPost:ResourceFetcherTests.ResourceFetcherSetHeader:ResourceFetcherTests.ResourceFetcherTimeout:SecurityExploitBrowserTest.AttemptDuplicateRenderViewHost:SecurityExploitBrowserTest.AttemptDuplicateRenderWidgetHost:SecurityExploitBrowserTest.InterstitialCommandFromUnderlyingContent:ServiceWorkerBrowserTest.CrossSiteTransfer:ServiceWorkerBrowserTest.ImportsBustMemcache:ServiceWorkerBrowserTest.Reload:ServiceWorkerBrowserTest.ResponseFromHTTPServiceWorkerIsNotMarkedAsSecure:ServiceWorkerBrowserTest.ResponseFromHTTPSServiceWorkerIsMarkedAsSecure:SessionHistoryTest.BasicBackForward:SessionHistoryTest.CrossFrameFormBackForward:SessionHistoryTest.FragmentBackForward:SessionHistoryTest.FrameBackForward:SessionHistoryTest.FrameFormBackForward:SessionHistoryTest.HistoryLength:SessionHistoryTest.JavascriptHistory:SessionHistoryTest.LocationChangeInSubframe:SessionHistoryTest.LocationReplace:SitePerProcessAccessibilityBrowserTest.CrossSiteIframeAccessibility:SitePerProcessBrowserTest.CleanupCrossSiteIframe:SitePerProcessBrowserTest.CompositorFrameSwapped:SitePerProcessBrowserTest.CreateProxiesForNewFrames:SitePerProcessBrowserTest.CrossSiteDidStopLoading:SitePerProcessBrowserTest.CrossSiteIframe:SitePerProcessBrowserTest.DynamicSandboxFlags:SitePerProcessBrowserTest.DynamicSandboxFlagsRemoteToLocal:SitePerProcessBrowserTest.KillingRendererClearsDescendantProxies:SitePerProcessBrowserTest.NavigateRemoteFrame:SitePerProcessBrowserTest.NavigateRemoteFrameToBlankAndDataURLs:SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcess:SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcessWithSubtree:SitePerProcessBrowserTest.NavigateWithSiblingRemoteFrame:SitePerProcessBrowserTest.OriginReplication:SitePerProcessBrowserTest.ProxyCreationSkipsSubtree:SitePerProcessBrowserTest.RestrictFrameDetach:SitePerProcessBrowserTest.SandboxFlagsReplication:SitePerProcessBrowserTest.SubframePostMessage:SitePerProcessDevToolsBrowserTest.CrossSiteIframeAgentHost:SpeechRecognitionBrowserTest.OneShotRecognition:StatsTableBrowserTest.StartWithStatTable:TracingControllerTest.EnableAndDisableRecording:TracingControllerTest.EnableAndDisableRecordingWithEmptyFileAndNullCallback:TracingControllerTest.EnableAndDisableRecordingWithFilePath:TracingControllerTest.EnableCaptureAndDisableMonitoring:TracingControllerTest.EnableCaptureAndDisableMonitoringWithEmptyFileAndNullCallback:TracingControllerTest.EnableCaptureAndDisableMonitoringWithFilePath:TracingControllerTest.GetCategories:TransitionBrowserTest.NormalNavigationNotDeferred:TransitionBrowserTest.TransitionNavigationDataIsCleared:TransitionBrowserTest.TransitionNavigationIsDeferred:WebContentsImplBrowserTest.ClearNonVisiblePendingOnFail:WebContentsImplBrowserTest.GetSizeForNewRenderView:WebContentsViewAuraTest.ScreenshotForSwappedOutRenderViews:WebRtcAecDumpBrowserTest.CallWithAecDump:WebRtcAecDumpBrowserTest.CallWithAecDumpEnabledThenDisabled:WebRtcAecDumpBrowserTest.TwoCallsWithAecDump:WebUIMojoTest.EndToEndPing:WorkerTest.IncognitoSharedWorkers:WorkerTest.MultipleSharedWorkers:WorkerTest.MultipleWorkers:WorkerTest.PassMessagePortToSharedWorker:WorkerTest.PassMessagePortToSharedWorkerDontWaitForConnect:WorkerTest.SharedWorkerTlsClientAuth:WorkerTest.SingleSharedWorker:WorkerTest.SingleWorker:WorkerTest.WorkerTlsClientAuth" ], "test": "content_browsertests" }, { "args": [ "--enable-browser-side-navigation", - "--gtest_filter=-DevToolsManagerTest.ReattachOnCancelPendingNavigation:NavigationControllerTest.CopyRestoredStateAndNavigate:NavigationControllerTest.LoadURL_AbortDoesntCancelPending:NavigationControllerTest.LoadURL_IgnorePreemptsPending:NavigationControllerTest.ReloadOriginalRequestURL:NavigationControllerTest.ShowRendererURLAfterFailUntilModified:NavigationControllerTest.ShowRendererURLInNewTabUntilModified:OverscrollNavigationOverlayTest.LoadUpdateWithoutNonEmptyPaint:RenderFrameHostManagerTest.AlwaysSendEnableViewSourceMode:RenderFrameHostManagerTest.CancelPendingProperlyDeletesOrSwaps:RenderFrameHostManagerTest.DetachPendingChild:RenderFrameHostManagerTest.PageDoesBackAndReload:RenderViewHostTest.ResetUnloadOnReload:ResourceDispatcherHostTest.TransferNavigationHtml:ResourceDispatcherHostTest.TransferNavigationText:ResourceDispatcherHostTest.TransferNavigationWithProcessCrash:ResourceDispatcherHostTest.TransferNavigationWithTwoRedirects:ResourceDispatcherHostTest.TransferTwoNavigationsHtml:WebContentsImplTest.ActiveContentsCountChangeBrowsingInstance:WebContentsImplTest.CrossSiteNavigationBackPreempted:WebContentsImplTest.CrossSiteNavigationCanceled:WebContentsImplTest.CrossSiteNavigationPreempted:WebContentsImplTest.CrossSiteNotPreemptedDuringBeforeUnload:WebContentsImplTest.NoEarlyStop" + "--gtest_filter=-NavigationControllerTest.CopyRestoredStateAndNavigate:NavigationControllerTest.LoadURL_AbortDoesntCancelPending:NavigationControllerTest.LoadURL_IgnorePreemptsPending:NavigationControllerTest.ShowRendererURLAfterFailUntilModified:NavigationControllerTest.ShowRendererURLInNewTabUntilModified:OverscrollNavigationOverlayTest.LoadUpdateWithoutNonEmptyPaint:RenderFrameHostManagerTest.CancelPendingProperlyDeletesOrSwaps:RenderFrameHostManagerTest.DetachPendingChild:RenderFrameHostManagerTest.PageDoesBackAndReload:RenderViewHostTest.ResetUnloadOnReload:ResourceDispatcherHostTest.TransferNavigationHtml:ResourceDispatcherHostTest.TransferNavigationText:ResourceDispatcherHostTest.TransferNavigationWithProcessCrash:ResourceDispatcherHostTest.TransferNavigationWithTwoRedirects:ResourceDispatcherHostTest.TransferTwoNavigationsHtml:WebContentsImplTest.CrossSiteNavigationBackPreempted:WebContentsImplTest.CrossSiteNavigationPreempted:WebContentsImplTest.CrossSiteNotPreemptedDuringBeforeUnload:WebContentsImplTest.NoEarlyStop" ], "test": "content_unittests" }
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json index 60a9e4c..2738e38 100644 --- a/testing/buildbot/chromium.linux.json +++ b/testing/buildbot/chromium.linux.json
@@ -1,4 +1,14 @@ { + "Android GN": { + "additional_compile_targets": [ + "all" + ], + "gtest_tests": [ + { + "test": "base_unittests" + } + ] + }, "Android Tests": { "scripts": [ { @@ -100,6 +110,26 @@ } ] }, + "Linux GN": { + "additional_compile_targets": [ + "all" + ], + "gtest_tests": [ + { + "test": "base_unittests" + } + ] + }, + "Linux GN (dbg)": { + "additional_compile_targets": [ + "all" + ], + "gtest_tests": [ + { + "test": "base_unittests" + } + ] + }, "Linux Tests": { "gtest_tests": [ {
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json index 89ff4e2..2907a38 100644 --- a/testing/buildbot/chromium.mac.json +++ b/testing/buildbot/chromium.mac.json
@@ -1,4 +1,24 @@ { + "Mac GN": { + "additional_compile_targets": [ + "all" + ], + "gtest_tests": [ + { + "test": "base_unittests" + } + ] + }, + "Mac GN (dbg)": { + "additional_compile_targets": [ + "all" + ], + "gtest_tests": [ + { + "test": "base_unittests" + } + ] + }, "Mac10.6 Tests": { "gtest_tests": [ {
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json index 582f21c..002e188 100644 --- a/testing/buildbot/chromium.win.json +++ b/testing/buildbot/chromium.win.json
@@ -983,6 +983,26 @@ } ] }, + "Win8 GN": { + "additional_compile_targets": [ + "all" + ], + "gtest_tests": [ + { + "test": "base_unittests" + } + ] + }, + "Win8 GN (dbg)": { + "additional_compile_targets": [ + "all" + ], + "gtest_tests": [ + { + "test": "base_unittests" + } + ] + }, "XP Tests (1)": { "gtest_tests": [ {
diff --git a/testing/buildbot/tryserver.chromium.linux.json b/testing/buildbot/tryserver.chromium.linux.json index 0967ef4..7ffe2c3e 100644 --- a/testing/buildbot/tryserver.chromium.linux.json +++ b/testing/buildbot/tryserver.chromium.linux.json
@@ -1 +1,62 @@ -{} +{ + "android_chromium_gn_compile_dbg": { + "additional_compile_targets": [ + "chrome_shell_apk" + ], + "gtest_tests": [ + { + "test": "base_unittests" + } + ] + }, + "android_chromium_gn_compile_rel": { + "additional_compile_targets": [ + "chrome_shell_apk" + ], + "gtest_tests": [ + { + "test": "base_unittests" + } + ] + }, + "linux_chromium_gn_chromeos_dbg": { + "additional_compile_targets": [ + "all" + ], + "gtest_tests": [ + { + "test": "base_unittests" + } + ] + }, + "linux_chromium_gn_chromeos_rel": { + "additional_compile_targets": [ + "all" + ], + "gtest_tests": [ + { + "test": "base_unittests" + } + ] + }, + "linux_chromium_gn_dbg": { + "additional_compile_targets": [ + "all" + ], + "gtest_tests": [ + { + "test": "base_unittests" + } + ] + }, + "linux_chromium_gn_rel": { + "additional_compile_targets": [ + "all" + ], + "gtest_tests": [ + { + "test": "base_unittests" + } + ] + } +}
diff --git a/testing/buildbot/tryserver.chromium.mac.json b/testing/buildbot/tryserver.chromium.mac.json index 66724b36..3e49ba2 100644 --- a/testing/buildbot/tryserver.chromium.mac.json +++ b/testing/buildbot/tryserver.chromium.mac.json
@@ -1,7 +1,17 @@ { "mac_chromium_gn_dbg": { "additional_compile_targets": [ - "gn_all" + "all" + ], + "gtest_tests": [ + { + "test": "base_unittests" + } + ] + }, + "mac_chromium_gn_rel": { + "additional_compile_targets": [ + "all" ], "gtest_tests": [ {
diff --git a/testing/buildbot/tryserver.chromium.win.json b/testing/buildbot/tryserver.chromium.win.json index 0967ef4..60650fa2 100644 --- a/testing/buildbot/tryserver.chromium.win.json +++ b/testing/buildbot/tryserver.chromium.win.json
@@ -1 +1,22 @@ -{} +{ + "win8_chromium_gn_dbg": { + "additional_compile_targets": [ + "all" + ], + "gtest_tests": [ + { + "test": "base_unittests" + } + ] + }, + "win8_chromium_gn_rel": { + "additional_compile_targets": [ + "all" + ], + "gtest_tests": [ + { + "test": "base_unittests" + } + ] + } +}
diff --git a/third_party/libjingle/README.chromium b/third_party/libjingle/README.chromium index 368f9e8..ccab606 100644 --- a/third_party/libjingle/README.chromium +++ b/third_party/libjingle/README.chromium
@@ -1,7 +1,7 @@ Name: libjingle URL: http://code.google.com/p/webrtc/ Version: unknown -Revision: 8975 +Revision: 8990 License: BSD License File: source/talk/COPYING Security Critical: yes
diff --git a/third_party/protobuf/README.chromium b/third_party/protobuf/README.chromium index c6bb5c2..e894d79 100644 --- a/third_party/protobuf/README.chromium +++ b/third_party/protobuf/README.chromium
@@ -40,3 +40,5 @@ in binary size. A BUILD.gn file has been added for building with GN. + +Cherry-pick pherl changes to make protobuf build on VS2015.
diff --git a/third_party/protobuf/src/google/protobuf/stubs/hash.h b/third_party/protobuf/src/google/protobuf/stubs/hash.h index f7d1071..82d5052e 100644 --- a/third_party/protobuf/src/google/protobuf/stubs/hash.h +++ b/third_party/protobuf/src/google/protobuf/stubs/hash.h
@@ -1,6 +1,6 @@ // Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. -// http://code.google.com/p/protobuf/ +// https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -37,13 +37,14 @@ #include <string.h> #include <google/protobuf/stubs/common.h> -#include "config.h" +#include <google/protobuf/stubs/pbconfig.h> -#if defined(HAVE_HASH_MAP) && defined(HAVE_HASH_SET) -#include HASH_MAP_H -#include HASH_SET_H +#if defined(GOOGLE_PROTOBUF_HAVE_HASH_MAP) && \ + defined(GOOGLE_PROTOBUF_HAVE_HASH_SET) +#include GOOGLE_PROTOBUF_HASH_MAP_H +#include GOOGLE_PROTOBUF_HASH_SET_H #else -#define MISSING_HASH +#define GOOGLE_PROTOBUF_MISSING_HASH #include <map> #include <set> #endif @@ -51,7 +52,7 @@ namespace google { namespace protobuf { -#ifdef MISSING_HASH +#ifdef GOOGLE_PROTOBUF_MISSING_HASH // This system doesn't have hash_map or hash_set. Emulate them using map and // set. @@ -88,15 +89,17 @@ template <typename Key, typename Data, typename HashFcn = hash<Key>, - typename EqualKey = int > -class hash_map : public std::map<Key, Data, HashFcn> { + typename EqualKey = std::equal_to<Key>, + typename Alloc = std::allocator< std::pair<const Key, Data> > > +class hash_map : public std::map<Key, Data, HashFcn, EqualKey, Alloc> { public: - hash_map(int = 0) {} + hash_map(int = 0, const HashFcn& = HashFcn(), const EqualKey& = EqualKey(), + const Alloc& = Alloc()) {} }; template <typename Key, typename HashFcn = hash<Key>, - typename EqualKey = int > + typename EqualKey = std::equal_to<Key> > class hash_set : public std::set<Key, HashFcn> { public: hash_set(int = 0) {} @@ -105,7 +108,7 @@ #elif defined(_MSC_VER) && !defined(_STLPORT_VERSION) template <typename Key> -struct hash : public HASH_NAMESPACE::hash_compare<Key> { +struct hash : public GOOGLE_PROTOBUF_HASH_NAMESPACE::hash_compare<Key> { }; // MSVC's hash_compare<const char*> hashes based on the string contents but @@ -119,23 +122,26 @@ template <> struct hash<const char*> - : public HASH_NAMESPACE::hash_compare<const char*, CstringLess> { -}; + : public GOOGLE_PROTOBUF_HASH_NAMESPACE::hash_compare< + const char*, CstringLess> {}; template <typename Key, typename Data, typename HashFcn = hash<Key>, - typename EqualKey = int > -class hash_map : public HASH_NAMESPACE::hash_map< - Key, Data, HashFcn> { + typename EqualKey = std::equal_to<Key>, + typename Alloc = std::allocator< std::pair<const Key, Data> > > +class hash_map + : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS< + Key, Data, HashFcn, EqualKey, Alloc> { public: - hash_map(int = 0) {} + hash_map(int = 0, const HashFcn& = HashFcn(), const EqualKey& = EqualKey(), + const Alloc& = Alloc()) {} }; -template <typename Key, - typename HashFcn = hash<Key>, - typename EqualKey = int > -class hash_set : public HASH_NAMESPACE::hash_set< - Key, HashFcn> { +template <typename Key, typename HashFcn = hash<Key>, + typename EqualKey = std::equal_to<Key> > +class hash_set + : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS< + Key, HashFcn, EqualKey> { public: hash_set(int = 0) {} }; @@ -143,7 +149,7 @@ #else template <typename Key> -struct hash : public HASH_NAMESPACE::hash<Key> { +struct hash : public GOOGLE_PROTOBUF_HASH_NAMESPACE::hash<Key> { }; template <typename Key> @@ -168,23 +174,27 @@ template <typename Key, typename Data, typename HashFcn = hash<Key>, - typename EqualKey = std::equal_to<Key> > -class hash_map : public HASH_NAMESPACE::HASH_MAP_CLASS< - Key, Data, HashFcn, EqualKey> { + typename EqualKey = std::equal_to<Key>, + typename Alloc = std::allocator< std::pair<const Key, Data> > > +class hash_map + : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS< + Key, Data, HashFcn, EqualKey, Alloc> { public: - hash_map(int = 0) {} + hash_map(int = 0, const HashFcn& = HashFcn(), const EqualKey& = EqualKey(), + const Alloc& = Alloc()) {} }; -template <typename Key, - typename HashFcn = hash<Key>, +template <typename Key, typename HashFcn = hash<Key>, typename EqualKey = std::equal_to<Key> > -class hash_set : public HASH_NAMESPACE::HASH_SET_CLASS< - Key, HashFcn, EqualKey> { +class hash_set + : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS< + Key, HashFcn, EqualKey> { public: hash_set(int = 0) {} }; -#endif +#undef GOOGLE_PROTOBUF_MISSING_HASH +#endif // !GOOGLE_PROTOBUF_MISSING_HASH template <> struct hash<string> {
diff --git a/third_party/protobuf/src/google/protobuf/stubs/pbconfig.h b/third_party/protobuf/src/google/protobuf/stubs/pbconfig.h new file mode 100644 index 0000000..1c0cfbe --- /dev/null +++ b/third_party/protobuf/src/google/protobuf/stubs/pbconfig.h
@@ -0,0 +1,74 @@ +/* Modified for Chromium to support stlport and libc++ adaptively */ +/* protobuf config.h for MSVC. On other platforms, this is generated + * automatically by autoheader / autoconf / configure. */ + +// NOTE: if you add new macros in this file manually, please propagate the macro +// to vsprojects/config.h. + +/* the namespace of hash_map/hash_set */ +// Apparently Microsoft decided to move hash_map *back* to the std namespace +// in MSVC 2010: +// http://blogs.msdn.com/vcblog/archive/2009/05/25/stl-breaking-changes-in-visual-studio-2010-beta-1.aspx +// And.. they are moved back to stdext in MSVC 2013 (haven't checked 2012). That +// said, use unordered_map for MSVC 2010 and beyond is our safest bet. +#if _MSC_VER >= 1600 +#define GOOGLE_PROTOBUF_HASH_NAMESPACE std +#define GOOGLE_PROTOBUF_HASH_MAP_H <unordered_map> +#define GOOGLE_PROTOBUF_HASH_MAP_CLASS unordered_map +#define GOOGLE_PROTOBUF_HASH_SET_H <unordered_set> +#define GOOGLE_PROTOBUF_HASH_SET_CLASS unordered_set +#elif _MSC_VER >= 1310 +#define GOOGLE_PROTOBUF_HASH_NAMESPACE stdext +#define GOOGLE_PROTOBUF_HASH_MAP_H <hash_map> +#define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map +#define GOOGLE_PROTOBUF_HASH_SET_H <hash_set> +#define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set +#else +/* the name of <hash_map> */ +#if defined(_LIBCPP_VERSION) +#define GOOGLE_PROTOBUF_HASH_MAP_CLASS unordered_map +#else +#define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map +#endif + +/* the location of <unordered_map> or <hash_map> */ +#if defined(USE_STLPORT) +#define GOOGLE_PROTOBUF_HASH_MAP_H <hash_map> +#elif defined(_LIBCPP_VERSION) +#define GOOGLE_PROTOBUF_HASH_MAP_H <unordered_map> +#else +#define GOOGLE_PROTOBUF_HASH_MAP_H <ext/hash_map> +#endif + +/* the namespace of hash_map/hash_set */ +#if defined(USE_STLPORT) || defined(_LIBCPP_VERSION) +#define GOOGLE_PROTOBUF_HASH_NAMESPACE std +#else +#define GOOGLE_PROTOBUF_HASH_NAMESPACE __gnu_cxx +#endif + +/* the name of <hash_set> */ +#if defined(_LIBCPP_VERSION) +#define GOOGLE_PROTOBUF_HASH_SET_CLASS unordered_set +#else +#define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set +#endif + +/* the location of <unordered_set> or <hash_set> */ +#if defined(USE_STLPORT) +#define GOOGLE_PROTOBUF_HASH_SET_H <hash_set> +#elif defined(_LIBCPP_VERSION) +#define GOOGLE_PROTOBUF_HASH_SET_H <unordered_set> +#else +#define GOOGLE_PROTOBUF_HASH_SET_H <ext/hash_set> +#endif + +#endif // _MSC_VER >= 1600 + +/* the location of <hash_set> */ + +/* define if the compiler has hash_map */ +#define GOOGLE_PROTOBUF_HAVE_HASH_MAP 1 + +/* define if the compiler has hash_set */ +#define GOOGLE_PROTOBUF_HAVE_HASH_SET 1
diff --git a/third_party/protobuf/vsprojects/config.h b/third_party/protobuf/vsprojects/config.h index 2c64450a..a93bb033 100644 --- a/third_party/protobuf/vsprojects/config.h +++ b/third_party/protobuf/vsprojects/config.h
@@ -1,28 +1,19 @@ /* protobuf config.h for MSVC. On other platforms, this is generated * automatically by autoheader / autoconf / configure. */ -/* the location of <hash_map> */ -#define HASH_MAP_H <hash_map> +#include <google/protobuf/stubs/pbconfig.h> -/* the namespace of hash_map/hash_set */ -// Apparently Microsoft decided to move hash_map *back* to the std namespace -// in MSVC 2010: -// http://blogs.msdn.com/vcblog/archive/2009/05/25/stl-breaking-changes-in-visual-studio-2010-beta-1.aspx -// TODO(kenton): Use unordered_map instead, which is available in MSVC 2010. -#if _MSC_VER < 1310 || _MSC_VER >= 1600 -#define HASH_NAMESPACE std -#else -#define HASH_NAMESPACE stdext +#define HASH_MAP_H GOOGLE_PROTOBUF_HASH_MAP_H +#define HASH_NAMESPACE GOOGLE_PROTOBUF_HASH_NAMESPACE +#define HASH_SET_H GOOGLE_PROTOBUF_HASH_SET_H + +#ifdef GOOGLE_PROTOBUF_HAVE_HASH_MAP +#define HAVE_HASH_MAP GOOGLE_PROTOBUF_HAVE_HASH_MAP #endif -/* the location of <hash_set> */ -#define HASH_SET_H <hash_set> - -/* define if the compiler has hash_map */ -#define HAVE_HASH_MAP 1 - -/* define if the compiler has hash_set */ -#define HAVE_HASH_SET 1 +#ifdef GOOGLE_PROTOBUF_HAVE_HASH_SET +#define HAVE_HASH_SET GOOGLE_PROTOBUF_HAVE_HASH_SET +#endif /* define if you want to use zlib. See readme.txt for additional * requirements. */
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/client_type.py b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/client_type.py index 83bc903..bd70d5b 100644 --- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/client_type.py +++ b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/client_type.py
@@ -39,36 +39,36 @@ # Page that should cause a bypass for android chrome clients. self.AddUserStory(ClientTypePage( - url='http://check.googlezip.net/chrome-proxy-header/c=ANDROID', + url='http://check.googlezip.net/chrome-proxy-header/c_android', page_set=self, bypass_for_client_type='android')) # Page that should cause a bypass for android webview clients. self.AddUserStory(ClientTypePage( - url='http://check.googlezip.net/chrome-proxy-header/c=WEBVIEW', + url='http://check.googlezip.net/chrome-proxy-header/c_webview', page_set=self, bypass_for_client_type='webview')) # Page that should cause a bypass for iOS clients. self.AddUserStory(ClientTypePage( - url='http://check.googlezip.net/chrome-proxy-header/c=IOS', + url='http://check.googlezip.net/chrome-proxy-header/c_ios', page_set=self, bypass_for_client_type='ios')) # Page that should cause a bypass for Linux clients. self.AddUserStory(ClientTypePage( - url='http://check.googlezip.net/chrome-proxy-header/c=LINUX', + url='http://check.googlezip.net/chrome-proxy-header/c_linux', page_set=self, bypass_for_client_type='linux')) # Page that should cause a bypass for Windows clients. self.AddUserStory(ClientTypePage( - url='http://check.googlezip.net/chrome-proxy-header/c=WIN', + url='http://check.googlezip.net/chrome-proxy-header/c_win', page_set=self, bypass_for_client_type='win')) # Page that should cause a bypass for ChromeOS clients. self.AddUserStory(ClientTypePage( - url='http://check.googlezip.net/chrome-proxy-header/c=CHROMEOS', + url='http://check.googlezip.net/chrome-proxy-header/c_chromeos', page_set=self, bypass_for_client_type='chromeos'))
diff --git a/tools/cygprofile/profile_android_startup.py b/tools/cygprofile/profile_android_startup.py index b23d2db7..f483dddf 100644 --- a/tools/cygprofile/profile_android_startup.py +++ b/tools/cygprofile/profile_android_startup.py
@@ -14,16 +14,26 @@ import shutil import subprocess import sys +import tempfile import time sys.path.append(os.path.join(sys.path[0], '..', '..', 'build', 'android')) from pylib import android_commands from pylib import constants from pylib import flag_changer +from pylib import forwarder from pylib.device import device_errors from pylib.device import device_utils from pylib.device import intent +sys.path.append(os.path.join(sys.path[0], '..', '..', 'tools', 'telemetry')) +from telemetry.core import webpagereplay + +sys.path.append(os.path.join(sys.path[0], '..', '..', + 'third_party', 'webpagereplay')) +import adb_install_cert +import certutils + class NoCyglogDataError(Exception): """An error used to indicate that no cyglog data was collected.""" @@ -36,15 +46,153 @@ return repr(self.value) +def _DownloadFromCloudStorage(bucket, sha1_file_name): + """Download the given file based on a hash file.""" + cmd = ['download_from_google_storage', '--no_resume', + '--bucket', bucket, '-s', sha1_file_name] + print 'Executing command ' + ' '.join(cmd) + process = subprocess.Popen(cmd) + process.wait() + if process.returncode != 0: + raise Exception('Exception executing command %s' % ' '.join(cmd)) + + +class WprManager(object): + """A utility to download a WPR archive, host it, and forward device ports to + it. + """ + + _WPR_BUCKET = 'chrome-partner-telemetry' + + def __init__(self, wpr_archive, device, cmdline_file): + self._device = device + self._wpr_archive = wpr_archive + self._wpr_archive_hash = wpr_archive + '.sha1' + self._cmdline_file = cmdline_file + self._wpr_server = None + self._wpr_ca_cert_path = None + self._device_cert_util = None + self._host_http_port = None + self._host_https_port = None + self._is_test_ca_installed = False + self._flag_changer = None + + def Start(self): + """Set up the device and host for WPR.""" + self.Stop() + self._InstallTestCa() + self._BringUpWpr() + self._StartForwarder() + + def Stop(self): + """Clean up the device and host's WPR setup.""" + self._StopForwarder() + self._StopWpr() + self._RemoveTestCa() + + def __enter__(self): + self.Start() + + def __exit__(self, unused_exc_type, unused_exc_val, unused_exc_tb): + self.Stop() + + def _InstallTestCa(self): + """Generates and deploys a test certificate authority.""" + print 'Installing test certificate authority on device: %s' % ( + self._device.adb.GetDeviceSerial()) + self._wpr_ca_cert_path = os.path.join(tempfile.mkdtemp(), 'testca.pem') + certutils.write_dummy_ca_cert(*certutils.generate_dummy_ca_cert(), + cert_path=self._wpr_ca_cert_path) + self._device_cert_util = adb_install_cert.AndroidCertInstaller( + self._device.adb.GetDeviceSerial(), None, self._wpr_ca_cert_path) + self._device_cert_util.install_cert(overwrite_cert=True) + self._is_test_ca_installed = True + + def _RemoveTestCa(self): + """Remove root CA generated by previous call to InstallTestCa(). + + Removes the test root certificate from both the device and host machine. + """ + print 'Cleaning up test CA...' + if not self._wpr_ca_cert_path: + return + + if self._is_test_ca_installed: + try: + self._device_cert_util.remove_cert() + except Exception: + # Best effort cleanup - show the error and continue. + logging.error( + 'Error while trying to remove certificate authority: %s. ' + % self._adb.device_serial()) + self._is_test_ca_installed = False + + shutil.rmtree(os.path.dirname(self._wpr_ca_cert_path), ignore_errors=True) + self._wpr_ca_cert_path = None + self._device_cert_util = None + + def _BringUpWpr(self): + """Start the WPR server on the host and the forwarder on the device.""" + print 'Starting WPR on host...' + _DownloadFromCloudStorage(self._WPR_BUCKET, self._wpr_archive_hash) + self._wpr_server = webpagereplay.ReplayServer(self._wpr_archive, + '127.0.0.1', 0, 0, None, + ['--should_generate_certs', + '--https_root_ca_cert_path=' + self._wpr_ca_cert_path, + '--use_closest_match']) + ports = self._wpr_server.StartServer()[:-1] + self._host_http_port = ports[0] + self._host_https_port = ports[1] + + def _StopWpr(self): + """ Stop the WPR and forwarder. """ + print 'Stopping WPR on host...' + if self._wpr_server: + self._wpr_server.StopServer() + + def _StartForwarder(self): + """Sets up forwarding of device ports to the host, and configures chrome + to use those ports. + """ + print 'Starting device forwarder...' + forwarder.Forwarder.Map([(0, self._host_http_port), + (0, self._host_https_port)], + self._device) + device_http = forwarder.Forwarder.DevicePortForHostPort( + self._host_http_port) + device_https = forwarder.Forwarder.DevicePortForHostPort( + self._host_https_port) + self._flag_changer = flag_changer.FlagChanger( + self._device, self._cmdline_file) + self._flag_changer.AddFlags([ + '--host-resolver-rules="MAP * 127.0.0.1,EXCLUDE localhost"', + '--testing-fixed-http-port=%s' % device_http, + '--testing-fixed-https-port=%s' % device_https]) + + def _StopForwarder(self): + """Shuts down the port forwarding service.""" + print 'Stopping device forwarder...' + if self._flag_changer: + self._flag_changer.Restore() + self._flag_changer = None + forwarder.Forwarder.UnmapAllDevicePorts(self._device) + + class AndroidProfileTool(object): - """ A utility for generating cygprofile data for chrome on andorid. + """A utility for generating cygprofile data for chrome on andorid. Runs cygprofile_unittest found in output_directory, does profiling runs, and pulls the data to the local machine in output_directory/cyglog_data. """ _DEVICE_CYGLOG_DIR = '/data/local/tmp/chrome/cyglog' + + # TEST_URL must be a url in the WPR_ARCHIVE. _TEST_URL = 'https://www.google.com/#hl=en&q=science' + _WPR_ARCHIVE = os.path.join( + constants.DIR_SOURCE_ROOT, 'tools', 'perf', 'page_sets', 'data', + 'top_10_mobile_002.wpr') + def __init__(self, output_directory): devices = android_commands.GetAttachedDevices() @@ -56,7 +204,7 @@ self._SetUpDevice() def RunCygprofileTests(self): - """ Run the cygprofile unit tests suite on the device. + """Run the cygprofile unit tests suite on the device. Args: path_to_tests: The location on the host machine with the compiled @@ -73,7 +221,7 @@ return exit_code def CollectProfile(self, apk, package_info): - """ Run a profile and collect the log files. + """Run a profile and collect the log files. Args: apk: The location of the chrome apk to profile. @@ -85,25 +233,31 @@ NoCyglogDataError: No data was found on the device. """ self._Install(apk, package_info) - self._SetChromeFlags(package_info) - self._SetUpDeviceFolders() - # Start up chrome once with a blank page, just to get the one-off - # activities out of the way such as apk resource extraction and profile - # creation. - self._StartChrome(package_info, 'about:blank') - time.sleep(15) - self._KillChrome(package_info) - self._SetUpDeviceFolders() - # TODO(azarchs): Set up WPR, device forwarding, test CA. - self._StartChrome(package_info, self._TEST_URL) - time.sleep(60) - self._KillChrome(package_info) + + try: + changer = self._SetChromeFlags(package_info) + self._SetUpDeviceFolders() + # Start up chrome once with a blank page, just to get the one-off + # activities out of the way such as apk resource extraction and profile + # creation. + self._StartChrome(package_info, 'about:blank') + time.sleep(15) + self._KillChrome(package_info) + self._SetUpDeviceFolders() + with WprManager(self._WPR_ARCHIVE, self._device, + package_info.cmdline_file): + self._StartChrome(package_info, self._TEST_URL) + time.sleep(90) + self._KillChrome(package_info) + finally: + self._RestoreChromeFlags(changer) + data = self._PullCyglogData() self._DeleteDeviceData() return data def Cleanup(self): - """ Delete all local and device files left over from profiling. """ + """Delete all local and device files left over from profiling. """ self._DeleteDeviceData() self._DeleteHostData() @@ -118,7 +272,7 @@ self._device.old_interface.ManagedInstall(apk, package_info.package) def _SetUpDevice(self): - """ When profiling, files are output to the disk by every process. This + """When profiling, files are output to the disk by every process. This means running without sandboxing enabled. """ # We need to have adb root in order to pull cyglog data @@ -135,22 +289,26 @@ logging.error(str(e)) def _SetChromeFlags(self, package_info): - print 'Setting flags...' + print 'Setting Chrome flags...' changer = flag_changer.FlagChanger( self._device, package_info.cmdline_file) changer.AddFlags(['--no-sandbox', '--disable-fre']) - # TODO(azarchs): backup and restore flags. - logging.warning('Chrome flags changed and will not be restored.') + return changer + + def _RestoreChromeFlags(self, changer): + print 'Restoring Chrome flags...' + if changer: + changer.Restore() def _SetUpDeviceFolders(self): - """ Creates folders on the device to store cyglog data. """ + """Creates folders on the device to store cyglog data. """ print 'Setting up device folders...' self._DeleteDeviceData() self._device.old_interface.RunShellCommand( 'mkdir -p %s' % self._DEVICE_CYGLOG_DIR) def _DeleteDeviceData(self): - """ Clears out cyglog storage locations on the device. """ + """Clears out cyglog storage locations on the device. """ self._device.old_interface.RunShellCommand( 'rm -rf %s' % self._DEVICE_CYGLOG_DIR) @@ -167,9 +325,7 @@ self._device.KillAll(package_info.package) def _DeleteHostData(self): - """ - Clears out cyglog storage locations on the host. - """ + """Clears out cyglog storage locations on the host.""" shutil.rmtree(self._host_cyglog_dir, ignore_errors=True) def _SetUpHostFolders(self): @@ -177,7 +333,7 @@ os.mkdir(self._host_cyglog_dir) def _PullCyglogData(self): - """ Pull the cyglog data off of the device. + """Pull the cyglog data off of the device. Returns: A list of cyglog data files which were pulled.
diff --git a/tools/gn/command_refs.cc b/tools/gn/command_refs.cc index e34efaac..832f53a 100644 --- a/tools/gn/command_refs.cc +++ b/tools/gn/command_refs.cc
@@ -34,20 +34,23 @@ } // Forward declaration for function below. -void RecursivePrintTargetDeps(const DepMap& dep_map, - const Target* target, - TargetSet* seen_targets, - int indent_level); +size_t RecursivePrintTargetDeps(const DepMap& dep_map, + const Target* target, + TargetSet* seen_targets, + int indent_level); // Prints the target and its dependencies in tree form. If the set is non-null, // new targets encountered will be added to the set, and if a ref is in the set // already, it will not be recused into. When the set is null, all refs will be // printed. -void RecursivePrintTarget(const DepMap& dep_map, +// +// Returns the number of items printed. +size_t RecursivePrintTarget(const DepMap& dep_map, const Target* target, TargetSet* seen_targets, int indent_level) { std::string indent(indent_level * 2, ' '); + size_t count = 1; // Only print the toolchain for non-default-toolchain targets. OutputString(indent + target->label().GetUserVisibleName( @@ -69,22 +72,28 @@ } OutputString("\n"); - if (print_children) - RecursivePrintTargetDeps(dep_map, target, seen_targets, indent_level + 1); + if (print_children) { + count += RecursivePrintTargetDeps(dep_map, target, seen_targets, + indent_level + 1); + } + return count; } // Prints refs of the given target (not the target itself). See // RecursivePrintTarget. -void RecursivePrintTargetDeps(const DepMap& dep_map, +size_t RecursivePrintTargetDeps(const DepMap& dep_map, const Target* target, TargetSet* seen_targets, int indent_level) { DepMap::const_iterator dep_begin = dep_map.lower_bound(target); DepMap::const_iterator dep_end = dep_map.upper_bound(target); + size_t count = 0; for (DepMap::const_iterator cur_dep = dep_begin; cur_dep != dep_end; cur_dep++) { - RecursivePrintTarget(dep_map, cur_dep->second, seen_targets, indent_level); + count += RecursivePrintTarget(dep_map, cur_dep->second, seen_targets, + indent_level); } + return count; } void RecursiveCollectChildRefs(const DepMap& dep_map, @@ -179,30 +188,35 @@ } } -void DoTreeOutput(const DepMap& dep_map, - const UniqueVector<const Target*>& implicit_target_matches, - const UniqueVector<const Target*>& explicit_target_matches, - bool all) { +// Returns the number of matches printed. +size_t DoTreeOutput(const DepMap& dep_map, + const UniqueVector<const Target*>& implicit_target_matches, + const UniqueVector<const Target*>& explicit_target_matches, + bool all) { TargetSet seen_targets; + size_t count = 0; // Implicit targets don't get printed themselves. for (const Target* target : implicit_target_matches) { if (all) - RecursivePrintTargetDeps(dep_map, target, nullptr, 0); + count += RecursivePrintTargetDeps(dep_map, target, nullptr, 0); else - RecursivePrintTargetDeps(dep_map, target, &seen_targets, 0); + count += RecursivePrintTargetDeps(dep_map, target, &seen_targets, 0); } // Explicit targets appear in the output. for (const Target* target : implicit_target_matches) { if (all) - RecursivePrintTarget(dep_map, target, nullptr, 0); + count += RecursivePrintTarget(dep_map, target, nullptr, 0); else - RecursivePrintTarget(dep_map, target, &seen_targets, 0); + count += RecursivePrintTarget(dep_map, target, &seen_targets, 0); } + + return count; } -void DoAllListOutput( +// Returns the number of matches printed. +size_t DoAllListOutput( const DepMap& dep_map, const UniqueVector<const Target*>& implicit_target_matches, const UniqueVector<const Target*>& explicit_target_matches) { @@ -218,9 +232,11 @@ } FilterAndPrintTargetSet(false, results); + return results.size(); } -void DoDirectListOutput( +// Returns the number of matches printed. +size_t DoDirectListOutput( const DepMap& dep_map, const UniqueVector<const Target*>& implicit_target_matches, const UniqueVector<const Target*>& explicit_target_matches) { @@ -241,6 +257,7 @@ results.insert(target); FilterAndPrintTargetSet(false, results); + return results.size(); } } // namespace @@ -294,6 +311,12 @@ "\n" TARGET_PRINTING_MODE_COMMAND_LINE_HELP "\n" + " -q\n" + " Quiet. If nothing matches, don't print any output. Without this\n" + " option, if there are no matches there will be an informational\n" + " message printed which might interfere with scripts processing the\n" + " output.\n" + "\n" TARGET_TESTONLY_FILTER_COMMAND_LINE_HELP "\n" " --tree\n" @@ -347,9 +370,9 @@ " potentially affected by a change to the given file.\n"; int RunRefs(const std::vector<std::string>& args) { - if (args.size() != 2) { + if (args.size() <= 1) { Err(Location(), "You're holding it wrong.", - "Usage: \"gn refs <out_dir> (<label_pattern>|<file>)\"") + "Usage: \"gn refs <out_dir> (<label_pattern>|<file>)*\"") .PrintToStdout(); return 1; } @@ -394,16 +417,35 @@ &explicit_target_matches); } + // Tell the user if their input matches no files or labels. We need to check + // both that it matched no targets and no configs. File input will already + // have been converted to targets at this point. Configs will have been + // converted to targets also, but there could be no targets referencing the + // config, which is different than no config with that name. + bool quiet = cmdline->HasSwitch("q"); + if (!quiet && config_matches.empty() && + explicit_target_matches.empty() && target_matches.empty()) { + OutputString("The input matches no targets, configs, or files.\n", + DECORATION_YELLOW); + return 1; + } + // Construct the reverse dependency tree. DepMap dep_map; FillDepMap(setup, &dep_map); + size_t cnt = 0; if (tree) - DoTreeOutput(dep_map, target_matches, explicit_target_matches, all); + cnt = DoTreeOutput(dep_map, target_matches, explicit_target_matches, all); else if (all) - DoAllListOutput(dep_map, target_matches, explicit_target_matches); + cnt = DoAllListOutput(dep_map, target_matches, explicit_target_matches); else - DoDirectListOutput(dep_map, target_matches, explicit_target_matches); + cnt = DoDirectListOutput(dep_map, target_matches, explicit_target_matches); + + // If you ask for the references of a valid target, but that target has + // nothing referencing it, we'll get here without having printed anything. + if (!quiet && cnt == 0) + OutputString("Nothing references this.\n", DECORATION_YELLOW); return 0; }
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index 6f26aed6..e9a28ec 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -147,10 +147,10 @@ 'Win8 GN (dbg)': 'gn_debug_bot', }, 'tryserver.chromium.linux': { - 'android_chromium_gn_dbg': 'android_gn_debug_bot', - 'android_chromium_gn_rel': 'android_gn_release_trybot', - 'linux_chromiumos_chromium_gn_rel': 'chromeos_gn_release_trybot', - 'linux_chromiumos_chromium_gn_dbg': 'chromeos_gn_debug_bot', + 'android_chromium_gn_compile_dbg': 'android_gn_debug_bot', + 'android_chromium_gn_compile_rel': 'android_gn_release_trybot', + 'linux_chromium_gn_chromeos_rel': 'chromeos_gn_release_trybot', + 'linux_chromium_gn_chromeos_dbg': 'chromeos_gn_debug_bot', 'linux_chromium_gn_dbg': 'gn_debug_bot', 'linux_chromium_gn_rel': 'gn_release_trybot', 'linux_chromium_gn_upload_x64': 'gn_release_bot',
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 8a0cd77..4d4e3ca 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -11306,7 +11306,7 @@ </summary> </histogram> -<histogram name="GPU.InitializeOneOffMediumTime" units="microseconds"> +<histogram name="GPU.InitializeOneOffMediumTime" units="milliseconds"> <owner>jmadill@chromium.org</owner> <summary> The time that the GPU process spends in initializing the GL surface, and @@ -23290,6 +23290,14 @@ </summary> </histogram> +<histogram name="Network.Shill.Wifi.SignalAtDisconnect" units="negative dBm"> + <owner>silberst@chromium.org</owner> + <summary> + Chrome OS network metric indicating the negative of the dBm received signal + strength recorded at the time of a WiFi disconnect. + </summary> +</histogram> + <histogram name="Network.Shill.Wifi.SignalStrength" units="negative dBm"> <owner>quiche@chromium.org</owner> <summary> @@ -34666,24 +34674,48 @@ </summary> </histogram> -<histogram name="ServiceWorker.StartWorker.Status" - units="ServiceWorkerStatusCode"> +<histogram name="ServiceWorker.StartNewWorker.Status" + enum="ServiceWorkerStatusCode"> <owner>falken@chromium.org</owner> - <summary>The result of trying to start a Service Worker.</summary> + <summary> + The result of trying to start a Service Worker that has not yet installed. + See also ServiceWorker.StartWorker.Status for installed workers. + </summary> +</histogram> + +<histogram name="ServiceWorker.StartNewWorker.Time" units="milliseconds"> + <owner>falken@chromium.org</owner> + <summary> + The time taken to start a Service Worker that has not yet installed, from + process allocation to ACK of started from the renderer (which occurs after + script execution). This may include script download time. The metric is not + recorded if DevTools was ever attached to the Service Worker during startup. + See also ServiceWorker.StartWorker.Time for installed workers. + </summary> +</histogram> + +<histogram name="ServiceWorker.StartWorker.Status" + enum="ServiceWorkerStatusCode"> + <owner>falken@chromium.org</owner> + <summary> + The result of trying to start a Service Worker that is already installed. + See also ServiceWorker.StartNewWorker.Status for new workers. + </summary> </histogram> <histogram name="ServiceWorker.StartWorker.Time" units="milliseconds"> <owner>falken@chromium.org</owner> <summary> - The time taken to start a Service Worker end-to-end, from process allocation - to ACK of started from the renderer. This possibly includes script download - time, but the metric is not recorded if DevTools was ever attached to the - Service Worker during startup. + The time taken to start a Service Worker that is already installed, from + process allocation to ACK of started from the renderer (which occurs after + script execution). The metric is not recorded if DevTools was ever attached + to the Service Worker during startup. See also + ServiceWorker.StartNewWorker.Time for new workers. </summary> </histogram> <histogram name="ServiceWorker.StartWorker.TimeoutPhase" - units="EmbeddedWorkerStartingPhase"> + enum="EmbeddedWorkerStartingPhase"> <owner>falken@chromium.org</owner> <summary> The phase the EmbeddedWorker was in when ServiceWorker startup timed out. @@ -38684,6 +38716,22 @@ </summary> </histogram> +<histogram name="Startup.AfterStartupTaskCount"> + <owner>michaeln@chromium.org</owner> + <summary> + The number of after-startup tasks that were queued prior to startup + completion and deferred until that time. + </summary> +</histogram> + +<histogram name="Startup.AfterStartupTaskDelayedUntilTime" units="milliseconds"> + <owner>michaeln@chromium.org</owner> + <summary> + Time from the process creation until deferred after-startup tasks began + running. + </summary> +</histogram> + <histogram name="Startup.AppListFirstPaintColdStart" units="milliseconds"> <owner>tapted@chromium.org</owner> <summary> @@ -40924,6 +40972,42 @@ </summary> </histogram> +<histogram name="Tabs.TabCountActiveWindow" units="Tabs"> + <owner>bruthig@chromium.org</owner> + <owner>tdanderson@chromium.org</owner> + <summary> + The number of tabs open in the active window when a load completes. + </summary> +</histogram> + +<histogram name="Tabs.TabCountPerLoad" units="Tabs"> + <owner>bruthig@chromium.org</owner> + <owner>tdanderson@chromium.org</owner> + <summary> + The number of tabs open in all browsers (counting app-mode windows) when a + load completes. + </summary> + <details> + This is basically the average number of tabs over time. + + See also MPArch.RPHCountPerLoad for the number of processes used by these + tabs. + </details> +</histogram> + +<histogram name="Tabs.TabCountPerWindow" units="Tabs"> + <owner>bruthig@chromium.org</owner> + <owner>tdanderson@chromium.org</owner> + <summary> + The number of tabs open per window (counting app-mode windows) when a load + completes. + </summary> + <details> + This value will be recorded multiple times per load if more than one window + is open. + </details> +</histogram> + <histogram name="ThreadWatcher.ResponseTime" units="milliseconds"> <owner>rtenneti@chromium.org</owner> <summary> @@ -45069,6 +45153,44 @@ </summary> </histogram> +<histogram name="WindowManager.AppWindowCountPerLoad"> + <owner>kuscher@chromium.org</owner> + <summary> + The number of app windows open when a load completes. This includes windows + opened by an app shortcut, or apps opened in a popup. This only counts v1 + apps. + </summary> +</histogram> + +<histogram name="WindowManager.PanelWindowCountPerLoad"> + <obsolete> + Deprecated 4/2013. No longer tracked. + </obsolete> + <owner>kuscher@chromium.org</owner> + <summary> + The number of panel windows open when a load completes. Panels are windows + docked to the bottom of the OS desktop, which are visible to the user even + while the user is interacting with other applications. + </summary> +</histogram> + +<histogram name="WindowManager.PopUpWindowCountPerLoad"> + <owner>kuscher@chromium.org</owner> + <summary> + The number of popup windows open when a load completes. Popup windows only + have one content area (no multiple tabs) and a stripped down toolbar + consisting only of a read-only address bar. + </summary> +</histogram> + +<histogram name="WindowManager.TabbedWindowCountPerLoad"> + <owner>kuscher@chromium.org</owner> + <summary> + The number of tabbed windows open when a load completes. A tabbed window is + a normal browser window which can have one or more tabs. + </summary> +</histogram> + <histogram name="Windows.Tablet" enum="BooleanTablet"> <owner>zturner@chromium.org</owner> <summary>Count of browser launches from a Windows tablet pc.</summary>
diff --git a/tools/perf/benchmarks/dromaeo.py b/tools/perf/benchmarks/dromaeo.py index b0f7d60c..ef5ed07 100644 --- a/tools/perf/benchmarks/dromaeo.py +++ b/tools/perf/benchmarks/dromaeo.py
@@ -212,6 +212,7 @@ return 'dromaeo.jslibeventjquery' +@benchmark.Disabled('android', 'linux') # http://crbug.com/476592 class DromaeoJslibEventPrototype(_DromaeoBenchmark): """Dromaeo JSLib event prototype JavaScript benchmark.
diff --git a/tools/perf/benchmarks/oilpan_gc_times.py b/tools/perf/benchmarks/oilpan_gc_times.py index 6f55e1e..f1577f9 100644 --- a/tools/perf/benchmarks/oilpan_gc_times.py +++ b/tools/perf/benchmarks/oilpan_gc_times.py
@@ -5,7 +5,6 @@ import os from telemetry import benchmark -from telemetry.core import util from telemetry import page from benchmarks import blink_perf
diff --git a/tools/perf/benchmarks/smoothness.py b/tools/perf/benchmarks/smoothness.py index 01aae239..0110866 100644 --- a/tools/perf/benchmarks/smoothness.py +++ b/tools/perf/benchmarks/smoothness.py
@@ -51,7 +51,7 @@ return 'smoothness.tough_canvas_cases' -@benchmark.Disabled('android', 'mac') # crbug.com/373812 +@benchmark.Disabled('android') # crbug.com/373812 class SmoothnessToughWebGLCases(benchmark.Benchmark): test = smoothness.Smoothness page_set = page_sets.ToughWebglCasesPageSet
diff --git a/tools/perf/benchmarks/startup.py b/tools/perf/benchmarks/startup.py index 41b08f0..5a37272 100644 --- a/tools/perf/benchmarks/startup.py +++ b/tools/perf/benchmarks/startup.py
@@ -60,9 +60,6 @@ @benchmark.Enabled('has tabs') @benchmark.Enabled('win', 'linux', 'mac') -# TODO(erikchen): Investigate source of 30s browser hang on startup. -# http://crbug.com/473827 -@benchmark.Disabled class StartupLargeProfileColdBlankPage(_StartupCold): """Measures cold startup time with a large profile.""" tag = 'cold' @@ -73,15 +70,15 @@ super(StartupLargeProfileColdBlankPage, self).__init__(max_failures) self.generated_profile_archive = "large_profile.zip" + def CustomizeBrowserOptions(self, options): + options.browser_startup_timeout = 10 * 60 + @classmethod def Name(cls): return 'startup.large_profile.cold.blank_page' @benchmark.Enabled('has tabs') @benchmark.Enabled('win', 'linux', 'mac') -# TODO(erikchen): Investigate source of 30s browser hang on startup. -# http://crbug.com/473827 -@benchmark.Disabled class StartupLargeProfileWarmBlankPage(_StartupWarm): """Measures warm startup time with a large profile.""" tag = 'warm' @@ -92,6 +89,9 @@ super(StartupLargeProfileWarmBlankPage, self).__init__(max_failures) self.generated_profile_archive = "large_profile.zip" + def CustomizeBrowserOptions(self, options): + options.browser_startup_timeout = 10 * 60 + @classmethod def Name(cls): return 'startup.large_profile.warm.blank_page'
diff --git a/tools/perf/measurements/oilpan_gc_times_unittest.py b/tools/perf/measurements/oilpan_gc_times_unittest.py index 45f1e56..8e9a2cbd 100644 --- a/tools/perf/measurements/oilpan_gc_times_unittest.py +++ b/tools/perf/measurements/oilpan_gc_times_unittest.py
@@ -19,9 +19,8 @@ 'file://blank.html', page_set, page_set.base_dir) def RunPageInteractions(self, action_runner): - interaction = action_runner.BeginGestureInteraction('ScrollAction') - action_runner.ScrollPage() - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage() class OilpanGCTimesTestData(object):
diff --git a/tools/perf/measurements/task_execution_time_unittest.py b/tools/perf/measurements/task_execution_time_unittest.py index e2137e1..827377f 100644 --- a/tools/perf/measurements/task_execution_time_unittest.py +++ b/tools/perf/measurements/task_execution_time_unittest.py
@@ -21,10 +21,8 @@ 'file://blank.html', page_set, base_dir) def RunPageInteractions(self, action_runner): - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollPage() - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage() class TaskExecutionTimeUnitTest(page_test_test_case.PageTestTestCase):
diff --git a/tools/perf/page_sets/key_desktop_sites.py b/tools/perf/page_sets/key_desktop_sites.py index 77e3465..7e9b0cc6 100644 --- a/tools/perf/page_sets/key_desktop_sites.py +++ b/tools/perf/page_sets/key_desktop_sites.py
@@ -13,10 +13,8 @@ self.archive_data_file = 'data/key_desktop_sites.json' def RunPageInteractions(self, action_runner): - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollPage() - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage() class FacebookPage(KeyDesktopSitesPage): @@ -45,10 +43,8 @@ self.credentials = 'google' def RunPageInteractions(self, action_runner): - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollPage() - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage() action_runner.WaitForJavaScriptCondition( 'window.gmonkey !== undefined && ' 'document.getElementById("gb") !== null') @@ -82,10 +78,8 @@ self.credentials = 'google' def RunPageInteractions(self, action_runner): - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollPage() - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage() action_runner.WaitForJavaScriptCondition( 'document.getElementsByClassName("doclistview-list").length') @@ -105,10 +99,8 @@ self.credentials = 'google' def RunPageInteractions(self, action_runner): - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollPage() - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage() action_runner.WaitForJavaScriptCondition( 'document.getElementsByClassName("kix-appview-editor").length')
diff --git a/tools/perf/page_sets/key_mobile_sites_smooth.py b/tools/perf/page_sets/key_mobile_sites_smooth.py index 9136e6e..8f55751 100644 --- a/tools/perf/page_sets/key_mobile_sites_smooth.py +++ b/tools/perf/page_sets/key_mobile_sites_smooth.py
@@ -8,10 +8,8 @@ def _IssueMarkerAndScroll(action_runner): - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollPage() - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage() def _CreatePageClassWithSmoothInteractions(page_cls): @@ -73,72 +71,60 @@ class GmailSmoothPage(key_mobile_sites_pages.GmailPage): def RunPageInteractions(self, action_runner): - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollElement(element_function=( - 'document.getElementById("views").childNodes[1].firstChild')) - interaction.End() - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollElement(element_function=( - 'document.getElementById("views").childNodes[1].firstChild')) - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollElement(element_function=( + 'document.getElementById("views").childNodes[1].firstChild')) + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollElement(element_function=( + 'document.getElementById("views").childNodes[1].firstChild')) class GroupClonedSmoothPage(key_mobile_sites_pages.GroupClonedPage): def RunPageInteractions(self, action_runner): - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollPage( - distance_expr=''' - Math.max(0, 1250 + document.getElementById("element-19") - .contentDocument - .getElementById("element-22") - .getBoundingClientRect().top);''', - use_touch=True) - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage( + distance_expr=''' + Math.max(0, 1250 + document.getElementById("element-19") + .contentDocument + .getElementById("element-22") + .getBoundingClientRect().top);''', + use_touch=True) class GroupClonedListImagesPage( key_mobile_sites_pages.GroupClonedListImagesPage): def RunPageInteractions(self, action_runner): - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollPage( - distance_expr=''' - Math.max(0, 1250 + - document.getElementById("element-5") - .getBoundingClientRect().top);''', - use_touch=True) - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage( + distance_expr=''' + Math.max(0, 1250 + + document.getElementById("element-5") + .getBoundingClientRect().top);''', + use_touch=True) class GoogleNewsMobile2SmoothPage( key_mobile_sites_pages.GoogleNewsMobile2Page): def RunPageInteractions(self, action_runner): - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollElement( - element_function='document.getElementById(":5")', - distance_expr=''' - Math.max(0, 2500 + - document.getElementById(':h').getBoundingClientRect().top)''', - use_touch=True) - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollElement( + element_function='document.getElementById(":5")', + distance_expr=''' + Math.max(0, 2500 + + document.getElementById(':h').getBoundingClientRect().top)''', + use_touch=True) class AmazonNicolasCageSmoothPage( key_mobile_sites_pages.AmazonNicolasCagePage): def RunPageInteractions(self, action_runner): - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollElement( - selector='#search', - distance_expr='document.body.scrollHeight - window.innerHeight') - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollElement( + selector='#search', + distance_expr='document.body.scrollHeight - window.innerHeight') class KeyMobileSitesSmoothPageSet(page_set_module.PageSet):
diff --git a/tools/perf/page_sets/key_search_mobile.py b/tools/perf/page_sets/key_search_mobile.py index 0535790e..2e5242e 100644 --- a/tools/perf/page_sets/key_search_mobile.py +++ b/tools/perf/page_sets/key_search_mobile.py
@@ -14,10 +14,8 @@ self.archive_data_file = 'data/key_search_mobile.json' def RunPageInteractions(self, action_runner): - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollPage() - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage() class KeySearchMobilePageSet(page_set_module.PageSet):
diff --git a/tools/perf/page_sets/mobile_memory.py b/tools/perf/page_sets/mobile_memory.py index fc03bee..3e3e822d 100644 --- a/tools/perf/page_sets/mobile_memory.py +++ b/tools/perf/page_sets/mobile_memory.py
@@ -47,25 +47,17 @@ page_set=page_set) def RunPageInteractions(self, action_runner): - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollPage() - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage() action_runner.Wait(3) - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollPage() - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage() action_runner.Wait(3) - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollPage() - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage() action_runner.Wait(3) - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollPage() - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage() action_runner.WaitForJavaScriptCondition( 'document.getElementById("rg_s").childElementCount > 300') @@ -76,10 +68,8 @@ super(ScrollPage, self).__init__(url=url, page_set=page_set) def RunPageInteractions(self, action_runner): - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollPage() - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage() class MobileMemoryPageSet(page_set_module.PageSet):
diff --git a/tools/perf/page_sets/pathological_mobile_sites.py b/tools/perf/page_sets/pathological_mobile_sites.py index da4134de..d508735e7 100644 --- a/tools/perf/page_sets/pathological_mobile_sites.py +++ b/tools/perf/page_sets/pathological_mobile_sites.py
@@ -14,10 +14,8 @@ self.archive_data_file = 'data/pathological_mobile_sites.json' def RunPageInteractions(self, action_runner): - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollPage() - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage() class PathologicalMobileSitesPageSet(page_set_module.PageSet):
diff --git a/tools/perf/page_sets/simple_mobile_sites.py b/tools/perf/page_sets/simple_mobile_sites.py index 50fc0ae8..be6fc8da 100644 --- a/tools/perf/page_sets/simple_mobile_sites.py +++ b/tools/perf/page_sets/simple_mobile_sites.py
@@ -26,10 +26,8 @@ def RunPageInteractions(self, action_runner): # Make the scroll longer to reduce noise. - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollPage(direction='down', speed_in_pixels_per_second=300) - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage(direction='down', speed_in_pixels_per_second=300) class SimpleMobileSitesPageSet(page_set_module.PageSet):
diff --git a/tools/perf/page_sets/simple_mobile_sites_fling.py b/tools/perf/page_sets/simple_mobile_sites_fling.py index 1e56165..bc44765 100644 --- a/tools/perf/page_sets/simple_mobile_sites_fling.py +++ b/tools/perf/page_sets/simple_mobile_sites_fling.py
@@ -25,13 +25,12 @@ action_runner.Wait(5) def RunPageInteractions(self, action_runner): - interaction = action_runner.BeginGestureInteraction('FlingAction') - # Swiping up induces a downward fling, and 500 pixels of touch scrolling - # runway ensures consistent fling velocities. - action_runner.SwipePage(direction='up', - distance='500', - speed_in_pixels_per_second=5000) - interaction.End() + with action_runner.CreateGestureInteraction('FlingAction'): + # Swiping up induces a downward fling, and 500 pixels of touch scrolling + # runway ensures consistent fling velocities. + action_runner.SwipePage(direction='up', + distance='500', + speed_in_pixels_per_second=5000) class SimpleMobileSitesFlingPageSet(page_set_module.PageSet):
diff --git a/tools/perf/page_sets/top_10_mobile.py b/tools/perf/page_sets/top_10_mobile.py index a9f5ae8..a18048c3 100644 --- a/tools/perf/page_sets/top_10_mobile.py +++ b/tools/perf/page_sets/top_10_mobile.py
@@ -17,10 +17,8 @@ def RunPageInteractions(self, action_runner): if self._run_no_page_interactions: return - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollPage() - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage() class Top10MobilePageSet(page_set_module.PageSet):
diff --git a/tools/perf/page_sets/tough_compositor_cases.py b/tools/perf/page_sets/tough_compositor_cases.py index cbf585da4..66cc32c3 100644 --- a/tools/perf/page_sets/tough_compositor_cases.py +++ b/tools/perf/page_sets/tough_compositor_cases.py
@@ -25,10 +25,8 @@ def RunPageInteractions(self, action_runner): # Make the scroll longer to reduce noise. - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollPage(direction='down', speed_in_pixels_per_second=300) - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage(direction='down', speed_in_pixels_per_second=300) class ToughCompositorWaitPage(ToughCompositorPage):
diff --git a/tools/perf/page_sets/tough_scheduling_cases.py b/tools/perf/page_sets/tough_scheduling_cases.py index b30b8ee..275f470 100644 --- a/tools/perf/page_sets/tough_scheduling_cases.py +++ b/tools/perf/page_sets/tough_scheduling_cases.py
@@ -14,10 +14,8 @@ self.archive_data_file = 'data/tough_scheduling_cases.json' def RunPageInteractions(self, action_runner): - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollPage() - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage() class Page1(ToughSchedulingCasesPage): @@ -308,15 +306,13 @@ page_set=page_set) def RunPageInteractions(self, action_runner): - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollElement( - selector='#card', - use_touch=True, - direction='up', - speed_in_pixels_per_second=150, - distance=400) - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollElement( + selector='#card', + use_touch=True, + direction='up', + speed_in_pixels_per_second=150, + distance=400) class EmptyTouchHandlerPage(ToughSchedulingCasesPage): @@ -339,18 +335,14 @@ def RunPageInteractions(self, action_runner): if self.bounce: - interaction = action_runner.BeginGestureInteraction( - 'ScrollBounceAction') - action_runner.ScrollBouncePage() - interaction.End() + with action_runner.CreateGestureInteraction('ScrollBounceAction'): + action_runner.ScrollBouncePage() else: - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - # Speed and distance are tuned to run exactly as long as a scroll - # bounce. - action_runner.ScrollPage(use_touch=True, speed_in_pixels_per_second=400, - distance=2100) - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + # Speed and distance are tuned to run exactly as long as a scroll + # bounce. + action_runner.ScrollPage(use_touch=True, speed_in_pixels_per_second=400, + distance=2100) class SynchronizedScrollOffsetPage(ToughSchedulingCasesPage): @@ -363,10 +355,8 @@ page_set=page_set) def RunPageInteractions(self, action_runner): - interaction = action_runner.BeginGestureInteraction( - 'ScrollBounceAction') - action_runner.ScrollBouncePage() - interaction.End() + with action_runner.CreateGestureInteraction('ScrollBounceAction'): + action_runner.ScrollBouncePage() class SecondBatchJsPage(ToughSchedulingCasesPage): @@ -387,15 +377,14 @@ # even while resources are being loaded. action_runner.WaitForJavaScriptCondition('window.__ready !== undefined') - interaction = action_runner.BeginGestureInteraction('LoadAction') - action_runner.ExecuteJavaScript('kickOffLoading()') - action_runner.WaitForJavaScriptCondition('window.__ready') - # Click one second after the resources have finished loading. - action_runner.Wait(1) - action_runner.TapElement(selector='input[id="run"]') - # Wait for the test to complete. - action_runner.WaitForJavaScriptCondition('window.__finished') - interaction.End() + with action_runner.CreateGestureInteraction('LoadAction'): + action_runner.ExecuteJavaScript('kickOffLoading()') + action_runner.WaitForJavaScriptCondition('window.__ready') + # Click one second after the resources have finished loading. + action_runner.Wait(1) + action_runner.TapElement(selector='input[id="run"]') + # Wait for the test to complete. + action_runner.WaitForJavaScriptCondition('window.__finished') class ToughSchedulingCasesPageSet(page_set_module.PageSet):
diff --git a/tools/perf/page_sets/tough_scrolling_while_zoomed_in_cases.py b/tools/perf/page_sets/tough_scrolling_while_zoomed_in_cases.py index 14a79fdc..243e25a 100644 --- a/tools/perf/page_sets/tough_scrolling_while_zoomed_in_cases.py +++ b/tools/perf/page_sets/tough_scrolling_while_zoomed_in_cases.py
@@ -30,14 +30,13 @@ # 10,000 was chosen to complete this pre-step quickly. # Then start measurements - interaction = action_runner.BeginGestureInteraction('ScrollAction') - # And begin the diagonal scroll - action_runner.ScrollPage( - direction='downright', - speed_in_pixels_per_second=10000) + with action_runner.CreateGestureInteraction('ScrollAction'): + # And begin the diagonal scroll + action_runner.ScrollPage( + direction='downright', # 10,000 was chosen because it is fast enough to completely stress the # rasterization (on a Nexus 5) without saturating results. - interaction.End() + speed_in_pixels_per_second=10000) class ToughScrollingWhileZoomedInCasesPageSet(page_set_module.PageSet):
diff --git a/tools/perf/page_sets/tough_texture_upload_cases.py b/tools/perf/page_sets/tough_texture_upload_cases.py index 1972896..2cef31d 100644 --- a/tools/perf/page_sets/tough_texture_upload_cases.py +++ b/tools/perf/page_sets/tough_texture_upload_cases.py
@@ -15,10 +15,8 @@ page_set=page_set) def RunPageInteractions(self, action_runner): - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollPage() - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage() class ToughTextureUploadCasesPageSet(page_set_module.PageSet):
diff --git a/tools/perf/page_sets/typical_25.py b/tools/perf/page_sets/typical_25.py index cdd78bb..da527e28 100644 --- a/tools/perf/page_sets/typical_25.py +++ b/tools/perf/page_sets/typical_25.py
@@ -16,10 +16,8 @@ def RunPageInteractions(self, action_runner): if self._run_no_page_interactions: return - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - action_runner.ScrollPage() - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage() class Typical25PageSet(page_set_module.PageSet):
diff --git a/tools/perf/profile_creators/fast_navigation_profile_extender.py b/tools/perf/profile_creators/fast_navigation_profile_extender.py index 0beb62e0..7fa222a 100644 --- a/tools/perf/profile_creators/fast_navigation_profile_extender.py +++ b/tools/perf/profile_creators/fast_navigation_profile_extender.py
@@ -83,6 +83,25 @@ """ pass + @property + def profile_path(self): + return self._profile_path + + def _AddNewTab(self): + """Adds a new tab to the browser.""" + + # Adding a new tab requires making a request over devtools. This can fail + # for a variety of reasons. Retry 3 times. + retry_count = 3 + for i in range(retry_count): + try: + self._navigation_tabs.append(self._browser.tabs.New()) + except exceptions.Error: + if i == retry_count - 1: + raise + else: + break + def _RefreshNavigationTabs(self): """Updates the member self._navigation_tabs to contain self._NUM_TABS elements, each of which is not crashed. The crashed tabs are intentionally @@ -97,7 +116,7 @@ self._navigation_tabs = live_tabs while len(self._navigation_tabs) < self._NUM_TABS: - self._navigation_tabs.append(self.browser.tabs.New()) + self._AddNewTab() def _RemoveNavigationTab(self, tab): """Removes a tab which is no longer in a useable state from
diff --git a/tools/telemetry/telemetry/core/backends/chrome/android_browser_finder.py b/tools/telemetry/telemetry/core/backends/chrome/android_browser_finder.py index 8df3b30..447853f 100644 --- a/tools/telemetry/telemetry/core/backends/chrome/android_browser_finder.py +++ b/tools/telemetry/telemetry/core/backends/chrome/android_browser_finder.py
@@ -49,7 +49,7 @@ android_browser_backend_settings.ChromeBackendSettings, None], 'android-chrome-dev': - ['com.chrome.dev', + ['com.google.android.apps.chrome_dev', android_browser_backend_settings.ChromeBackendSettings, None], 'android-chrome-canary':
diff --git a/tools/telemetry/telemetry/core/backends/chrome/tab_list_backend.py b/tools/telemetry/telemetry/core/backends/chrome/tab_list_backend.py index 0e97113..480b6e7c 100644 --- a/tools/telemetry/telemetry/core/backends/chrome/tab_list_backend.py +++ b/tools/telemetry/telemetry/core/backends/chrome/tab_list_backend.py
@@ -28,7 +28,7 @@ self._browser_backend.devtools_client.CreateNewTab(timeout) return self[-1] - def CloseTab(self, tab_id, timeout=None): + def CloseTab(self, tab_id, timeout=30): """Closes the tab with the given debugger_url. Raises: @@ -50,7 +50,7 @@ util.WaitFor(lambda: tab_id not in self, timeout=5) - def ActivateTab(self, tab_id, timeout=None): + def ActivateTab(self, tab_id, timeout=30): """Activates the tab with the given debugger_url. Raises:
diff --git a/tools/telemetry/telemetry/core/backends/chrome_inspector/devtools_http.py b/tools/telemetry/telemetry/core/backends/chrome_inspector/devtools_http.py index 006d4e87..fecd768 100644 --- a/tools/telemetry/telemetry/core/backends/chrome_inspector/devtools_http.py +++ b/tools/telemetry/telemetry/core/backends/chrome_inspector/devtools_http.py
@@ -69,6 +69,8 @@ Raises: DevToolsClientConnectionError: If the connection fails. """ + assert timeout + if not self._conn: self._Connect(timeout)
diff --git a/tools/telemetry/telemetry/core/browser_options.py b/tools/telemetry/telemetry/core/browser_options.py index 16fb585..9a800556 100644 --- a/tools/telemetry/telemetry/core/browser_options.py +++ b/tools/telemetry/telemetry/core/browser_options.py
@@ -117,10 +117,6 @@ help='Record profiling data using this tool. Supported values: ' + ', '.join(profiler_choices)) group.add_option( - '--interactive', dest='interactive', action='store_true', - help='Let the user interact with the page; the actions specified for ' - 'the page are not run.') - group.add_option( '-v', '--verbose', action='count', dest='verbosity', help='Increase verbosity level (repeat as needed)') group.add_option('--print-bootstrap-deps',
diff --git a/tools/telemetry/telemetry/core/tab_list.py b/tools/telemetry/telemetry/core/tab_list.py index da83d699..e692723 100644 --- a/tools/telemetry/telemetry/core/tab_list.py +++ b/tools/telemetry/telemetry/core/tab_list.py
@@ -5,7 +5,7 @@ def __init__(self, tab_list_backend): self._tab_list_backend = tab_list_backend - def New(self, timeout=None): + def New(self, timeout=30): return self._tab_list_backend.New(timeout) def __iter__(self):
diff --git a/tools/telemetry/telemetry/page/page_test.py b/tools/telemetry/telemetry/page/page_test.py index bc5eb3e..019f492 100644 --- a/tools/telemetry/telemetry/page/page_test.py +++ b/tools/telemetry/telemetry/page/page_test.py
@@ -207,14 +207,10 @@ def RunPage(self, page, tab, results): # Run actions. - interactive = self.options and self.options.interactive action_runner = action_runner_module.ActionRunner( tab, skip_waits=page.skip_waits) self.WillRunActions(page, tab) - if interactive: - action_runner.PauseInteractive() - else: - page.RunPageInteractions(action_runner) + page.RunPageInteractions(action_runner) self.DidRunActions(page, tab) self.ValidateAndMeasurePage(page, tab, results)
diff --git a/tools/telemetry/telemetry/unittest_util/page_test_test_case.py b/tools/telemetry/telemetry/unittest_util/page_test_test_case.py index 5e82a7a..8e1e1bdc 100644 --- a/tools/telemetry/telemetry/unittest_util/page_test_test_case.py +++ b/tools/telemetry/telemetry/unittest_util/page_test_test_case.py
@@ -23,9 +23,8 @@ super(BasicTestPage, self).__init__(url, page_set, base_dir) def RunPageInteractions(self, action_runner): - interaction = action_runner.BeginGestureInteraction('ScrollAction') - action_runner.ScrollPage() - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage() class EmptyMetadataForTest(benchmark.BenchmarkMetadata):
diff --git a/tools/telemetry/telemetry/web_perf/smooth_gesture_util_unittest.py b/tools/telemetry/telemetry/web_perf/smooth_gesture_util_unittest.py index a305f396..e3702e6 100644 --- a/tools/telemetry/telemetry/web_perf/smooth_gesture_util_unittest.py +++ b/tools/telemetry/telemetry/web_perf/smooth_gesture_util_unittest.py
@@ -102,14 +102,12 @@ super(ScrollingPage, self).__init__(url, page_set, base_dir) def RunPageInteractions(self, action_runner): - interaction = action_runner.BeginGestureInteraction( - 'ScrollAction') - # Add 0.5s gap between when Gesture records are issued to when we actually - # scroll the page. - time.sleep(0.5) - action_runner.ScrollPage() - time.sleep(0.5) - interaction.End() + with action_runner.CreateGestureInteraction('ScrollAction'): + # Add 0.5s gap between when Gesture records are issued to when we actually + # scroll the page. + time.sleep(0.5) + action_runner.ScrollPage() + time.sleep(0.5) class SmoothGestureTest(page_test_test_case.PageTestTestCase):
diff --git a/tools/telemetry/telemetry/web_perf/timeline_based_page_test_unittest.py b/tools/telemetry/telemetry/web_perf/timeline_based_page_test_unittest.py index 4e5f386..68d4b8c 100644 --- a/tools/telemetry/telemetry/web_perf/timeline_based_page_test_unittest.py +++ b/tools/telemetry/telemetry/web_perf/timeline_based_page_test_unittest.py
@@ -35,9 +35,8 @@ action_runner.TapElement('#slow-button') action_runner.WaitForJavaScriptCondition('window.slowScriptDone') if self._trigger_scroll_gesture: - interaction = action_runner.BeginGestureInteraction('Scroll') - action_runner.ScrollPage() - interaction.End() + with action_runner.CreateGestureInteraction('Scroll'): + action_runner.ScrollPage() class TimelineBasedPageTestTest(page_test_test_case.PageTestTestCase):
diff --git a/tools/valgrind/drmemory/suppressions.txt b/tools/valgrind/drmemory/suppressions.txt index 59e01847..272d0c9 100644 --- a/tools/valgrind/drmemory/suppressions.txt +++ b/tools/valgrind/drmemory/suppressions.txt
@@ -766,3 +766,20 @@ *!base::internal::InvokeHelper<>::MakeItSo *!base::internal::Invoker<>::Run *!content::ManifestFetcher::OnLoadComplete + +UNADDRESSABLE ACCESS +name=http://crbug.com/476586 +*!blink::WebFrameWidgetImpl::beginFrame +*!content::RenderWidgetCompositor::BeginMainFrame +*!cc::LayerTreeHost::BeginMainFrame +*!cc::ThreadProxy::BeginMainFrame +*!base::internal::InvokeHelper<>::MakeItSo + +UNADDRESSABLE ACCESS +name=http://crbug.com/476586b +*!blink::PageWidgetDelegate::animate +*!blink::WebFrameWidgetImpl::beginFrame +*!content::RenderWidgetCompositor::BeginMainFrame +*!cc::LayerTreeHost::BeginMainFrame +*!cc::ThreadProxy::BeginMainFrame +*!base::internal::InvokeHelper<>::MakeItSo
diff --git a/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt b/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt index f5dcbb0d..ecb31e45 100644 --- a/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt +++ b/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt
@@ -137,6 +137,8 @@ Pe* Plat*Bro* Policy*H* +# PopupBlockerBrowserTest.TapGestureWithCtrlKey +Pop* Port* Prefe* PrefsF*
diff --git a/tools/valgrind/gtest_exclude/cc_unittests.gtest-drmemory_win32.txt b/tools/valgrind/gtest_exclude/cc_unittests.gtest-drmemory_win32.txt index 01234982..7946e976 100644 --- a/tools/valgrind/gtest_exclude/cc_unittests.gtest-drmemory_win32.txt +++ b/tools/valgrind/gtest_exclude/cc_unittests.gtest-drmemory_win32.txt
@@ -10,7 +10,7 @@ # http://crbug.com/416643 LayerTreeHostCopyRequestTestMultipleRequests.GLRenderer_RunSingleThread LayerTreeHostCopyRequestTestMultipleRequests.SoftwareRenderer_RunSingleThread -LayerTreeHostTestReadyToDrawNonEmpty.RunSingleThread_DelegatingRenderer_ImplSidePaint +LayerTreeHostTestReadyToDrawNonEmpty.* LayerTreeHostTestMaxTransferBufferUsageBytes.* # http://crbug.com/430400
diff --git a/tools/valgrind/gtest_exclude/unit_tests.gtest-memcheck.txt b/tools/valgrind/gtest_exclude/unit_tests.gtest-memcheck.txt index 4e2b8ec..bae79ce 100644 --- a/tools/valgrind/gtest_exclude/unit_tests.gtest-memcheck.txt +++ b/tools/valgrind/gtest_exclude/unit_tests.gtest-memcheck.txt
@@ -16,3 +16,6 @@ # Test fail: crbug.com/473689 ManagePasswordsBubbleModelTest.CloseWithoutLogging + +# Test fail: crbug.com/476731 +PluginInfoMessageFilterTest.FindEnabledPlugin
diff --git a/ui/base/ime/input_method_chromeos.cc b/ui/base/ime/input_method_chromeos.cc index aef3e9f..6b07c21 100644 --- a/ui/base/ime/input_method_chromeos.cc +++ b/ui/base/ime/input_method_chromeos.cc
@@ -371,7 +371,10 @@ if (client != GetTextInputClient()) return; - if (event.type() == ET_KEY_PRESSED && !handled) + if (handled) + return; // IME handled the key event. do not forward. + + if (event.type() == ET_KEY_PRESSED) ProcessUnfilteredKeyPressEvent(event); else if (event.type() == ET_KEY_RELEASED) DispatchKeyEventPostIME(event);
diff --git a/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc b/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc index b5fc0d9..3327114 100644 --- a/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc +++ b/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc
@@ -25,10 +25,6 @@ #include "ui/events/ozone/evdev/libgestures_glue/gesture_feedback.h" #include "ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.h" -// Severity level for general info logging purpose. -#define GPROP_LOG DVLOG -#define INFO_SEVERITY 1 - // GesturesProp implementation. // // Check the header file for its definition. @@ -180,7 +176,7 @@ void InitializeNumericalProperty(const T* init, const GesturesProp* default_property) { if (IsDefaultPropertyUsable(default_property)) { - GPROP_LOG(INFO_SEVERITY) << "Default property found. Using its value ..."; + DVLOG(2) << "Default property found. Using its value ..."; this->template SetNumericalValue(default_property->GetDoubleValue()); } else { // To work with the interface exposed by the gesture lib, we have no @@ -364,7 +360,7 @@ const GesturesProp* default_property) { // Initialize the property value similar to the numerical types. if (IsDefaultPropertyUsable(default_property)) { - GPROP_LOG(INFO_SEVERITY) << "Default property found. Using its value ..."; + DVLOG(2) << "Default property found. Using its value ..."; *value_ = default_property->GetStringValue(); } else { *value_ = init; @@ -1002,13 +998,13 @@ path = file_enum.Next()) { files.insert(path); } - GPROP_LOG(INFO_SEVERITY) << files.size() << " conf files were found"; + DVLOG(2) << files.size() << " conf files were found"; // Parse conf files one-by-one. for (std::set<base::FilePath>::iterator file_iter = files.begin(); file_iter != files.end(); ++file_iter) { - GPROP_LOG(INFO_SEVERITY) << "Parsing conf file: " << (*file_iter).value(); + DVLOG(2) << "Parsing conf file: " << (*file_iter).value(); std::string content; if (!base::ReadFileToString(*file_iter, &content)) { LOG(ERROR) << "Can't loading gestures conf file: " @@ -1096,12 +1092,12 @@ has_error = true; is_input_class_section = false; } else { - GPROP_LOG(INFO_SEVERITY) << "New InputClass section found"; + DVLOG(2) << "New InputClass section found"; has_checked_section_type = true; } break; } else if (next_is_identifier) { - GPROP_LOG(INFO_SEVERITY) << "Identifier: " << arg; + DVLOG(2) << "Identifier: " << arg; config->identifier = arg; next_is_identifier = false; break; @@ -1191,8 +1187,7 @@ internal::MatchCriteria* GesturePropertyProvider::CreateMatchCriteria( const std::string& match_type, const std::string& arg) { - GPROP_LOG(INFO_SEVERITY) << "Creating match criteria: (" << match_type << ", " - << arg << ")"; + DVLOG(2) << "Creating match criteria: (" << match_type << ", " << arg << ")"; if (match_type == "MatchProduct") return new internal::MatchProduct(arg); if (match_type == "MatchDevicePath") @@ -1222,8 +1217,7 @@ // 5. The property is treated as numeric if and only if all of its elements // (if any) are numerics. Otherwise, it will be treated as a string. // 6. A string property will be trimmed before storing its value. - GPROP_LOG(INFO_SEVERITY) << "Creating default property: (" << name << ", " - << value << ")"; + DVLOG(2) << "Creating default property: (" << name << ", " << value << ")"; // Parse elements one-by-one. std::string delimiters(base::kWhitespaceASCII); @@ -1264,7 +1258,7 @@ property = new GesturesStringProp(name, NULL, value.c_str(), NULL); } - GPROP_LOG(INFO_SEVERITY) << "Prop: " << *property; + DVLOG(2) << "Prop: " << *property; // The function will always succeed for now but it may change later if we // specify some name or args as invalid. return property; @@ -1272,18 +1266,16 @@ void GesturePropertyProvider::SetupDefaultProperties(const DeviceId device_id, const DevicePtr device) { - GPROP_LOG(INFO_SEVERITY) << "Setting up default properties for (" << device - << ", " << device_id << ", " << device->info.name - << ")"; + DVLOG(2) << "Setting up default properties for (" << device << ", " + << device_id << ", " << device->info.name << ")"; // Go through all parsed sections. internal::PropertiesMap& property_map = device_data_map_.get(device_id)->default_properties; for (size_t i = 0; i < configurations_.size(); ++i) { if (configurations_[i]->Match(device)) { - GPROP_LOG(INFO_SEVERITY) << "Conf section \"" - << configurations_[i]->identifier - << "\" is matched"; + DVLOG(2) << "Conf section \"" << configurations_[i]->identifier + << "\" is matched"; for (size_t j = 0; j < configurations_[i]->properties.size(); j++) { GesturesProp* property = configurations_[i]->properties[j]; // We can't use insert here because a property may be set for several @@ -1366,7 +1358,7 @@ // No need to manually delete the prop pointer as it is implicitly handled // with scoped ptr. - GPROP_LOG(3) << "Freeing Property: \"" << property->name() << "\""; + DVLOG(3) << "Freeing Property: \"" << property->name() << "\""; provider->DeleteProperty(GetDeviceId(device_data), property->name()); } @@ -1478,7 +1470,7 @@ provider->RegisterDevice(device_id, GetDevicePointer(device_data)); // First, see if the GesturesProp already exists. - GPROP_LOG(3) << "Creating Property: \"" << name << "\""; + DVLOG(3) << "Creating Property: \"" << name << "\""; GesturesProp* property = provider->FindProperty(device_id, name); // If so, delete it as we can't reuse the data structure (newly-created @@ -1504,7 +1496,7 @@ provider->AddProperty(GetDeviceId(device_data), name, property); // Log the creation. - GPROP_LOG(INFO_SEVERITY) << "Created active prop: " << *property; + DVLOG(3) << "Created active prop: " << *property; } GesturesProp* GesturesPropFunctionsWrapper::CreateIntSingle(void* device_data,
diff --git a/ui/native_theme/native_theme_win.cc b/ui/native_theme/native_theme_win.cc index b3326dd..aee3c46 100644 --- a/ui/native_theme/native_theme_win.cc +++ b/ui/native_theme/native_theme_win.cc
@@ -1512,7 +1512,7 @@ const DTBGOPTS value_draw_options = { sizeof(DTBGOPTS), (bar_rect.right == value_rect.right && bar_rect.left != value_rect.left) ? - DTBG_MIRRORDC : 0, + DTBG_MIRRORDC : 0u, bar_rect }; if (pre_vista) {
diff --git a/ui/ozone/platform/drm/gpu/drm_display_snapshot.cc b/ui/ozone/platform/drm/gpu/drm_display_snapshot.cc index 96e0a2f..4c906542 100644 --- a/ui/ozone/platform/drm/gpu/drm_display_snapshot.cc +++ b/ui/ozone/platform/drm/gpu/drm_display_snapshot.cc
@@ -83,12 +83,7 @@ nullptr), drm_(drm), connector_(connector->connector_id), - crtc_(crtc->crtc_id), - dpms_property_(drm->GetProperty(connector, "DPMS")) { - if (!dpms_property_) - VLOG(1) << "Failed to find the DPMS property for connector " - << connector->connector_id; - + crtc_(crtc->crtc_id) { ScopedDrmPropertyBlobPtr edid_blob(drm->GetPropertyBlob(connector, "EDID")); if (edid_blob) {
diff --git a/ui/ozone/platform/drm/gpu/drm_display_snapshot.h b/ui/ozone/platform/drm/gpu/drm_display_snapshot.h index 62ad1fe..e79f9a4 100644 --- a/ui/ozone/platform/drm/gpu/drm_display_snapshot.h +++ b/ui/ozone/platform/drm/gpu/drm_display_snapshot.h
@@ -26,7 +26,6 @@ // configuring this display. uint32_t connector() const { return connector_; } uint32_t crtc() const { return crtc_; } - drmModePropertyRes* dpms_property() const { return dpms_property_.get(); } // DisplaySnapshot overrides: std::string ToString() const override; @@ -35,7 +34,6 @@ scoped_refptr<DrmDevice> drm_; uint32_t connector_; uint32_t crtc_; - ScopedDrmPropertyPtr dpms_property_; std::string name_; bool overscan_flag_;
diff --git a/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc b/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc index 60b335b..9a1d7cc4 100644 --- a/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc +++ b/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc
@@ -306,19 +306,7 @@ << " connector=" << output.connector(); return false; } - - if (output.dpms_property()) { - output.drm()->SetProperty(output.connector(), - output.dpms_property()->prop_id, - DRM_MODE_DPMS_ON); - } } else { - if (output.dpms_property()) { - output.drm()->SetProperty(output.connector(), - output.dpms_property()->prop_id, - DRM_MODE_DPMS_OFF); - } - if (!screen_manager_->DisableDisplayController(output.drm(), output.crtc())) { VLOG(1) << "Failed to disable device="
diff --git a/ui/ozone/platform/drm/gpu/drm_util.cc b/ui/ozone/platform/drm/gpu/drm_util.cc index 01b82a2..517a58c 100644 --- a/ui/ozone/platform/drm/gpu/drm_util.cc +++ b/ui/ozone/platform/drm/gpu/drm_util.cc
@@ -136,18 +136,11 @@ if (displays.empty()) return; - ScopedDrmPropertyPtr dpms(drm->GetProperty(displays[0]->connector(), "DPMS")); - screen_manager->AddDisplayController(drm, displays[0]->crtc()->crtc_id, displays[0]->connector()->connector_id); - if (screen_manager->ConfigureDisplayController( - drm, displays[0]->crtc()->crtc_id, - displays[0]->connector()->connector_id, gfx::Point(), - displays[0]->connector()->modes[0])) { - if (dpms) - drm->SetProperty(displays[0]->connector()->connector_id, dpms->prop_id, - DRM_MODE_DPMS_ON); - } + screen_manager->ConfigureDisplayController( + drm, displays[0]->crtc()->crtc_id, displays[0]->connector()->connector_id, + gfx::Point(), displays[0]->connector()->modes[0]); } base::FilePath GetPrimaryDisplayCardPath() {
diff --git a/ui/platform_window/win/win_window.cc b/ui/platform_window/win/win_window.cc index 9bc8892..debf105 100644 --- a/ui/platform_window/win/win_window.cc +++ b/ui/platform_window/win/win_window.cc
@@ -115,7 +115,8 @@ tracked_objects::ScopedTracker tracking_profile( FROM_HERE_WITH_EXPLICIT_FUNCTION("440919 WinWindow::OnMouseRange")); - MSG msg = { hwnd(), message, w_param, l_param, GetMessageTime(), + MSG msg = { hwnd(), message, w_param, l_param, + static_cast<DWORD>(GetMessageTime()), { CR_GET_X_LPARAM(l_param), CR_GET_Y_LPARAM(l_param) } }; MouseEvent event(msg); if (IsMouseEventFromTouch(message))
diff --git a/ui/views/bubble/bubble_delegate_unittest.cc b/ui/views/bubble/bubble_delegate_unittest.cc index 782c9e79..ec5ab144 100644 --- a/ui/views/bubble/bubble_delegate_unittest.cc +++ b/ui/views/bubble/bubble_delegate_unittest.cc
@@ -242,6 +242,7 @@ test::TestWidgetObserver bubble_observer(bubble_widget); EXPECT_FALSE(bubble_observer.widget_closed()); + anchor_widget->Show(); bubble_widget->Show(); EXPECT_TRUE(bubble_widget->IsVisible()); anchor_widget->SetBounds(gfx::Rect(10, 10, 100, 100));
diff --git a/ui/views/controls/label_unittest.cc b/ui/views/controls/label_unittest.cc index b73083e..32fabd78 100644 --- a/ui/views/controls/label_unittest.cc +++ b/ui/views/controls/label_unittest.cc
@@ -177,9 +177,8 @@ Label label; base::string16 test_text = base::UTF8ToUTF16("\xF0\x9D\x84\x9E"); label.SetText(test_text); - label.SizeToPreferredSize(); - label.SetObscured(true); + label.SizeToPreferredSize(); EXPECT_EQ(ASCIIToUTF16("*"), label.GetDisplayTextForTesting()); EXPECT_EQ(test_text, label.text()); }
diff --git a/ui/views/linux_ui/linux_ui.h b/ui/views/linux_ui/linux_ui.h index 088de92..fa910d23 100644 --- a/ui/views/linux_ui/linux_ui.h +++ b/ui/views/linux_ui/linux_ui.h
@@ -154,6 +154,9 @@ // Updates the device scale factor so that the default font size can be // recalculated. virtual void UpdateDeviceScaleFactor(float device_scale_factor) = 0; + + // Determines the device scale factor of the primary screen. + virtual float GetDeviceScaleFactor() const = 0; }; } // namespace views
diff --git a/ui/views/widget/desktop_aura/desktop_screen_x11.cc b/ui/views/widget/desktop_aura/desktop_screen_x11.cc index 019688fb..fc477e6 100644 --- a/ui/views/widget/desktop_aura/desktop_screen_x11.cc +++ b/ui/views/widget/desktop_aura/desktop_screen_x11.cc
@@ -25,6 +25,7 @@ #include "ui/gfx/native_widget_types.h" #include "ui/gfx/screen.h" #include "ui/gfx/x/x11_types.h" +#include "ui/views/linux_ui/linux_ui.h" #include "ui/views/widget/desktop_aura/desktop_screen.h" #include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h" #include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h" @@ -35,21 +36,12 @@ // in |Dispatch()|. const int64 kConfigureDelayMs = 500; -// TODO(oshima): Consider using gtk-xft-dpi instead. -float GetDeviceScaleFactor(int screen_pixels, int screen_mm) { - const int kCSSDefaultDPI = 96; - const float kInchInMm = 25.4f; - - float screen_inches = screen_mm / kInchInMm; - float screen_dpi = screen_pixels / screen_inches; - float scale = screen_dpi / kCSSDefaultDPI; - - return ui::GetScaleForScaleFactor(ui::GetSupportedScaleFactor(scale)); -} - -float GetDeviceScaleFactor() { - gfx::Display display = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay(); - return display.device_scale_factor(); +double GetDeviceScaleFactor() { + float device_scale_factor = 1.0f; + if (views::LinuxUI::instance()) + device_scale_factor = + views::LinuxUI::instance()->GetDeviceScaleFactor(); + return device_scale_factor; } gfx::Point PixelToDIPPoint(const gfx::Point& pixel_point) { @@ -71,8 +63,7 @@ gfx::Display gfx_display(0, bounds_in_pixels); if (!gfx::Display::HasForceDeviceScaleFactor() && !ui::IsDisplaySizeBlackListed(physical_size)) { - float device_scale_factor = GetDeviceScaleFactor( - width, physical_size.width()); + const float device_scale_factor = GetDeviceScaleFactor(); DCHECK_LE(1.0f, device_scale_factor); gfx_display.SetScaleAndBounds(device_scale_factor, bounds_in_pixels); } @@ -294,7 +285,9 @@ has_work_area = true; } - float device_scale_factor = 1.0f; + // As per-display scale factor is not supported right now, + // the X11 root window's scale factor is always used. + const float device_scale_factor = GetDeviceScaleFactor(); for (int i = 0; i < resources->noutput; ++i) { RROutput output_id = resources->outputs[i]; gfx::XScopedPtr<XRROutputInfo, @@ -321,14 +314,6 @@ gfx::Display display(display_id, crtc_bounds); if (!gfx::Display::HasForceDeviceScaleFactor()) { - if (i == 0 && !ui::IsDisplaySizeBlackListed( - gfx::Size(output_info->mm_width, output_info->mm_height))) { - // As per display scale factor is not supported right now, - // the primary display's scale factor is always used. - device_scale_factor = GetDeviceScaleFactor(crtc->width, - output_info->mm_width); - DCHECK_LE(1.0f, device_scale_factor); - } display.SetScaleAndBounds(device_scale_factor, crtc_bounds); }
diff --git a/ui/views/window/custom_frame_view_unittest.cc b/ui/views/window/custom_frame_view_unittest.cc index fe20bf9..1320f48f 100644 --- a/ui/views/window/custom_frame_view_unittest.cc +++ b/ui/views/window/custom_frame_view_unittest.cc
@@ -196,7 +196,7 @@ title_bounds().x()); } -// Tests that layouts occuring while maximized swap the maximize button for the +// Tests that layouts occurring while maximized swap the maximize button for the // restore button TEST_F(CustomFrameViewTest, MaximizeRevealsRestoreButton) { Widget* parent = widget(); @@ -211,8 +211,15 @@ parent->Maximize(); view->Layout(); +#if defined(OS_MACOSX) + // Restore buttons do not exist on Mac. The maximize button is instead a kind + // of toggle, but has no effect on frame decorations. + EXPECT_FALSE(restore_button()->visible()); + EXPECT_TRUE(maximize_button()->visible()); +#else EXPECT_TRUE(restore_button()->visible()); EXPECT_FALSE(maximize_button()->visible()); +#endif } // Tests that when the parent cannot maximize that the maximize button is not @@ -271,10 +278,18 @@ parent->Maximize(); view->Layout(); +#if defined(OS_MACOSX) + // On Mac, "Maximize" should not alter the frame. Only fullscreen does that. + EXPECT_EQ(close_button()->bounds().width(), + close_button_initial_bounds.width()); + EXPECT_EQ(minimize_button()->bounds().width(), + minimize_button_initial_bounds.width()); +#else EXPECT_GT(close_button()->bounds().width(), close_button_initial_bounds.width()); EXPECT_GT(minimize_button()->bounds().width(), minimize_button_initial_bounds.width()); +#endif } } // namespace views
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.html b/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.html index 32f5be49..d9905fe4 100644 --- a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.html +++ b/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.html
@@ -1,4 +1,5 @@ <link rel="import" href="chrome://resources/polymer/polymer/polymer.html"> +<link rel="import" href="chrome://resources/cr_elements/cr_onc/cr_onc_data.html"> <polymer-element name="cr-network-icon"> <template>
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.js b/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.js index 322a7dc..35f5172 100644 --- a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.js +++ b/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.js
@@ -119,11 +119,16 @@ * network state. */ networkStateChanged: function() { - this.iconType = getIconTypeFromNetworkType(this.networkState.data.Type); var params = /** @type {IconParams} */ { - showBadges: true, - showDisconnected: !this.isListItem, - strength: this.networkState.getStrength(), + showBadges: false, + showDisconnected: true, + strength: 0, + }; + if (this.networkState) { + this.iconType = getIconTypeFromNetworkType(this.networkState.data.Type); + params.showBadges = true; + params.showDisconnected = !this.isListItem; + params.strength = this.networkState.getStrength(); }; this.setIcon_(params); },
diff --git a/ui/webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.css b/ui/webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.css new file mode 100644 index 0000000..828c09e --- /dev/null +++ b/ui/webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.css
@@ -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. */ + +#divOuter { + border-style: none; + display: flex; + flex-direction: row; + margin: 0; + padding: 4px; + width: 100%; +} + +#divOuter:hover { + background-color: lightgrey; +} + +#divIcon { + display: flex; + flex: 0 0 auto; + flex-direction: column; + justify-content: center; +} + +#icon { + height: 32px; + width: 32px; +} + +#divDetail { + display: flex; + flex: 1 0 auto; + flex-direction: row; +} + +#divText { + display: flex; + flex: 1 0 auto; + flex-direction: column; + justify-content: center; +} + +#networkName { + -webkit-margin-start: 8px; + font-size: 16px; +} + +#networkState { + -webkit-margin-start: 8px; + color: grey; + font-size: 14px; +} + +.connected { + font-weight: bold; +}
diff --git a/ui/webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.html b/ui/webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.html new file mode 100644 index 0000000..cd790f5 --- /dev/null +++ b/ui/webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.html
@@ -0,0 +1,19 @@ +<link rel="import" href="chrome://resources/polymer/polymer/polymer.html"> +<link rel="import" href="chrome://resources/cr_elements/cr_network_icon/cr_network_icon.html"> + +<polymer-element name="cr-network-list-item"> + <template> + <link rel="stylesheet" href="cr_network_list_item.css"> + <div id="divOuter"> + <div id="divIcon"> + <cr-network-icon id="icon" networkState="{{networkState}}"> + </cr-network-icon> + </div> + <div id="divText"> + <span id="networkName"></span> + <span id="networkState" hidden?="{{isListItem}}"></span> + </div> + </div> + </template> + <script src="cr_network_list_item.js"></script> +</polymer-element>
diff --git a/ui/webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.js b/ui/webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.js new file mode 100644 index 0000000..39786b7f --- /dev/null +++ b/ui/webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.js
@@ -0,0 +1,95 @@ +// 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. + +/** + * @fileoverview Polymer element for displaying information about a network + * in a list or summary based on ONC state properties. + */ +(function() { + +/** + * TODO(stevenjb): Replace getText with a proper localization function that + * handles string substitution. + * Performs argument substitution, replacing %1, %2, etc in 'text' with + * corresponding entries in |args|. + * @param {string} text The string to perform the substitution on. + * @param {Array<string>} args The arguments to replace %1, %2, etc with. + */ +function getText(text, args) { + var res = text; + if (!args) + return res; + for (var i = 0; i < args.length; ++i) { + var key = '%' + (i + 1); + res = res.replace(key, args[i]); + } + return res; +} + +/** + * Returns the appropriate connection state text. + * @param {string} state The connection state. + * @param {string} name The name of the network. + */ +function getConnectionStateText(state, name) { + if (state == 'Connected') + return getText('Connected to %1', [name]); + if (state == 'Connecting') + return getText('Connecting to %1...', [name]); + if (state == 'NotConnected') + return getText('Not Connected'); + return getText(state); +}; + +/** + * Polymer class definition for 'cr-network-list-item'. + * @element cr-network-list-item + */ +Polymer('cr-network-list-item', { + publish: { + /** + * The ONC data properties used to display the list item. + * + * @attribute networkState + * @type CrOncDataElement + * @default null + */ + networkState: null, + + /** + * If true, the element is part of a list of networks and only displays + * the network icon and name. Otherwise the element is assumed to be a + * stand-alone item (e.g. as part of a summary) and displays the name + * of the network type plus the network name and connection state. + * + * @attribute isListItem + * @type boolean + * @default false + */ + isListItem: false, + }, + + /** + * Polymer networkState changed method. Updates the element based on the + * network state. + */ + networkStateChanged: function() { + if (!this.networkState) + return; + + var network = this.networkState.data; + var isDisconnected = this.networkState.disconnected(); + if (this.isListItem) { + this.$.networkName.textContent = getText(network.Name); + this.$.networkName.classList.toggle('connected', !isDisconnected); + } else { + this.$.networkName.textContent = getText(network.Type); + this.$.networkName.classList.toggle('connected', false); + this.$.networkState.textContent = + getConnectionStateText(network.ConnectionState, network.Name); + this.$.networkState.classList.toggle('connected', !isDisconnected); + } + }, +}); +})();
diff --git a/ui/webui/resources/cr_elements/cr_onc/cr_onc_data.js b/ui/webui/resources/cr_elements/cr_onc/cr_onc_data.js index 1d87b74..978532f4 100644 --- a/ui/webui/resources/cr_elements/cr_onc/cr_onc_data.js +++ b/ui/webui/resources/cr_elements/cr_onc/cr_onc_data.js
@@ -37,6 +37,11 @@ return this.data.ConnectionState == CrOnc.ConnectionState.CONNECTING; }, + /** @return {boolean} True if the network is disconnected. */ + disconnected: function() { + return this.data.ConnectionState == CrOnc.ConnectionState.NOT_CONNECTED; + }, + /** @return {number} The signal strength of the network. */ getStrength: function() { var type = this.data.Type;
diff --git a/ui/webui/resources/cr_elements_resources.grdp b/ui/webui/resources/cr_elements_resources.grdp index f1b89bf..960cc81 100644 --- a/ui/webui/resources/cr_elements_resources.grdp +++ b/ui/webui/resources/cr_elements_resources.grdp
@@ -45,6 +45,15 @@ <structure name="IDR_CR_ELEMENTS_CR_NETWORK_ICON_JS" file="../../webui/resources/cr_elements/cr_network_icon/cr_network_icon.js" type="chrome_html" /> + <structure name="IDR_CR_ELEMENTS_CR_NETWORK_LIST_ITEM_CSS" + file="../../webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.css" + type="chrome_html" /> + <structure name="IDR_CR_ELEMENTS_CR_NETWORK_LIST_ITEM_HTML" + file="../../webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.html" + type="chrome_html" /> + <structure name="IDR_CR_ELEMENTS_CR_NETWORK_LIST_ITEM_JS" + file="../../webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.js" + type="chrome_html" /> <structure name="IDR_CR_ELEMENTS_CR_ONC_TYPES_JS" file="../../webui/resources/cr_elements/cr_onc/cr_onc_types.js" type="chrome_html" />
diff --git a/ui/webui/resources/js/compiled_resources.gyp b/ui/webui/resources/js/compiled_resources.gyp index 668413a6..40b1571 100644 --- a/ui/webui/resources/js/compiled_resources.gyp +++ b/ui/webui/resources/js/compiled_resources.gyp
@@ -50,7 +50,7 @@ 'includes': ['../../../../third_party/closure_compiler/compile_js.gypi'], }, { - 'target_name': 'i18n_template2', + 'target_name': 'i18n_template', 'variables': { 'depends': ['compiled_resources.gyp:load_time_data'], },
diff --git a/ui/webui/resources/js/cr/ui/list_selection_model.js b/ui/webui/resources/js/cr/ui/list_selection_model.js index 60f4106c..5b143d6d 100644 --- a/ui/webui/resources/js/cr/ui/list_selection_model.js +++ b/ui/webui/resources/js/cr/ui/list_selection_model.js
@@ -143,6 +143,9 @@ * Selects all indexes. */ selectAll: function() { + if (this.length === 0) + return; + this.selectRange(0, this.length - 1); },