diff --git a/.DEPS.git b/.DEPS.git new file mode 100644 index 0000000000000..1ce9d787927e6 --- /dev/null +++ b/.DEPS.git @@ -0,0 +1,783 @@ +# DO NOT EDIT EXCEPT FOR LOCAL TESTING. +# THIS IS A GENERATED FILE. +# ALL MANUAL CHANGES WILL BE OVERWRITTEN. +# SEE http://code.google.com/p/chromium/wiki/UsingGit +# FOR HOW TO ROLL DEPS +vars = { + 'eyes-free': + 'http://eyes-free.googlecode.com/svn', + 'webkit_rev': + '@045e2df1e88cddebce6d9690812b5233c896e201', + 'blink': + 'http://src.chromium.org/blink', + 'skia': + 'http://skia.googlecode.com/svn', + 'google-breakpad': + 'http://google-breakpad.googlecode.com/svn', + 'sawbuck': + 'http://sawbuck.googlecode.com/svn', + 'mozc': + 'http://mozc.googlecode.com/svn', + 'git.chromium.org': + 'https://chromium.googlesource.com', + 'v8-i18n': + 'http://v8-i18n.googlecode.com/svn', + 'selenium': + 'http://selenium.googlecode.com/svn', + 'buildspec_platforms': + 'all', + 'webkit_url': + 'https://chromium.googlesource.com/chromium/blink.git', + 'snappy': + 'http://snappy.googlecode.com/svn', + 'ppapi': + 'http://ppapi.googlecode.com/svn', + 'webrtc': + 'http://webrtc.googlecode.com/svn', + 'libaddressinput': + 'http://libaddressinput.googlecode.com/svn', + 'google-cache-invalidation-api': + 'http://google-cache-invalidation-api.googlecode.com/svn', + 'google-url': + 'http://google-url.googlecode.com/svn', + 'googletest': + 'http://googletest.googlecode.com/svn', + 'gyp': + 'http://gyp.googlecode.com/svn', + 'seccompsandbox': + 'http://seccompsandbox.googlecode.com/svn', + 'ots': + 'http://ots.googlecode.com/svn', + 'angleproject': + 'http://angleproject.googlecode.com/svn', + 'pefile': + 'http://pefile.googlecode.com/svn', + 'open-vcdiff': + 'http://open-vcdiff.googlecode.com/svn', + 'linux-syscall-support': + 'http://linux-syscall-support.googlecode.com/svn', + 'jsoncpp': + 'http://svn.code.sf.net/p/jsoncpp/code', + 'pywebsocket': + 'http://pywebsocket.googlecode.com/svn', + 'web-page-replay': + 'http://web-page-replay.googlecode.com/svn', + 'libjingle': + 'http://libjingle.googlecode.com/svn', + 'cld2': + 'https://cld2.googlecode.com/svn', + 'jsr-305': + 'http://jsr-305.googlecode.com/svn', + 'angle_revision': + '019fa9340e580e5836a9b9dc7cede4766cd090df', + 'bidichecker': + 'http://bidichecker.googlecode.com/svn', + 'git_url': + 'https://chromium.googlesource.com', + 'native_client': + 'http://src.chromium.org/native_client', + 'trace-viewer': + 'http://trace-viewer.googlecode.com/svn', + 'leveldb': + 'http://leveldb.googlecode.com/svn', + 'webkit_trunk': + 'http://src.chromium.org/blink/trunk', + 'googlemock': + 'http://googlemock.googlecode.com/svn', + 'grit-i18n': + 'http://grit-i18n.googlecode.com/svn', + 'pdfsqueeze': + 'http://pdfsqueeze.googlecode.com/svn', + 'protobuf': + 'http://protobuf.googlecode.com/svn', + 'smhasher': + 'http://smhasher.googlecode.com/svn', + 'google-toolbox-for-mac': + 'http://google-toolbox-for-mac.googlecode.com/svn', + 'libyuv': + 'http://libyuv.googlecode.com/svn', + 'rlz': + 'http://rlz.googlecode.com/svn', + 'v8': + 'http://v8.googlecode.com/svn', + 'octane-benchmark': + 'http://octane-benchmark.googlecode.com/svn', + 'sfntly': + 'http://sfntly.googlecode.com/svn', + 'sctp-refimpl': + 'https://sctp-refimpl.googlecode.com/svn', + 'libphonenumber': + 'http://libphonenumber.googlecode.com/svn', + 'pymox': + 'http://pymox.googlecode.com/svn', + 'pyftpdlib': + 'http://pyftpdlib.googlecode.com/svn', + 'google-safe-browsing': + 'http://google-safe-browsing.googlecode.com/svn' +} + +deps = { + 'build': + Var('git_url') + '/chromium/tools/build.git@4cf01c0b543771d924ddb315dc839a8f68ca5756', + 'build/scripts/command_wrapper/bin': + Var('git_url') + '/chromium/tools/command_wrapper/bin.git@2eeebba9a512cae9e4e9312f5ec728dbdad80bd0', + 'build/scripts/gsd_generate_index': + Var('git_url') + '/chromium/tools/gsd_generate_index.git@d2f5d5a5d212d8fb337d751c0351644a6ac83ac8', + 'build/scripts/private/data/reliability': + Var('git_url') + '/chromium/src/chrome/test/data/reliability.git@ba644102a2f81bb33582e9474a10812fef825389', + 'build/scripts/tools/deps2git': + Var('git_url') + '/chromium/tools/deps2git.git@27ce444f50f3c6732982d225d3f4cf67f0979a98', + 'build/third_party/lighttpd': + Var('git_url') + '/chromium/deps/lighttpd.git@9dfa55d15937a688a92cbf2b7a8621b0927d06eb', + 'depot_tools': + Var('git_url') + '/chromium/tools/depot_tools.git@45cddd65697e31dbafc8469b542b01a031a25df2', + 'src/breakpad/src': + Var('git_url') + '/external/google-breakpad/src.git@f37b59821ecbd69c54f3388026d2e98cd8b2fba2', + 'src/buildtools': + Var('git_url') + '/chromium/buildtools.git@c27f95bd1d9baaef70c879dea375090dd1496147', + 'src/chrome/browser/resources/pdf/html_office': + Var('git_url') + '/chromium/html-office-public.git@eeff97614f65e0578529490d44d412032c3d7359', + 'src/chrome/test/data/perf/canvas_bench': + Var('git_url') + '/chromium/canvas_bench.git@a7b40ea5ae0239517d78845a5fc9b12976bfc732', + 'src/chrome/test/data/perf/frame_rate/content': + Var('git_url') + '/chromium/frame_rate/content.git@c10272c88463efeef6bb19c9ec07c42bc8fe22b9', + 'src/media/cdm/ppapi/api': + Var('git_url') + '/chromium/cdm.git@f924b6382b05c57677455ac40f210b33809591ef', + 'src/native_client': + Var('git_url') + '/native_client/src/native_client.git@9cd80947288ebca86dd07b55171089b84553a7c7', + 'src/sdch/open-vcdiff': + Var('git_url') + '/external/open-vcdiff.git@438f2a5be6d809bc21611a94cd37bfc8c28ceb33', + 'src/testing/gmock': + Var('git_url') + '/external/googlemock.git@896ba0e03f520fb9b6ed582bde2bd00847e3c3f2', + 'src/testing/gtest': + Var('git_url') + '/external/googletest.git@4650552ff637bb44ecf7784060091cbed3252211', + 'src/third_party/WebKit': + Var('webkit_url') + '' + Var('webkit_rev'), + 'src/third_party/angle': + Var('git_url') + '/angle/angle.git' + '@' + Var('angle_revision'), + 'src/third_party/bidichecker': + Var('git_url') + '/external/bidichecker/lib.git@97f2aa645b74c28c57eca56992235c79850fa9e0', + 'src/third_party/boringssl/src': + 'https://boringssl.googlesource.com/boringssl.git@817ec3462e246b8301a73e44854e2bb3df90d5e6', + 'src/third_party/brotli/src': + Var('git_url') + '/external/font-compression-reference.git@65cb3326e30ef8a67eb1d4411ec563e91be6e9ae', + 'src/third_party/cacheinvalidation/src': + Var('git_url') + '/external/google-cache-invalidation-api/src.git@c91bd9d9fed06bf440be64f87b94a2effdb32bc4', + 'src/third_party/cld_2/src': + Var('git_url') + '/external/cld2.git@14d9ef8d4766326f8aa7de54402d1b9c782d4481', + 'src/third_party/colorama/src': + Var('git_url') + '/external/colorama.git@799604a1041e9b3bc5d2789ecbd7e8db2e18e6b8', + 'src/third_party/ffmpeg': + Var('git_url') + '/chromium/third_party/ffmpeg.git@399d38b9baba60763e1db26be5d6a8577a4276f4', + 'src/third_party/flac': + Var('git_url') + '/chromium/deps/flac.git@0635a091379d9677f1ddde5f2eec85d0f096f219', + 'src/third_party/hunspell': + Var('git_url') + '/chromium/deps/hunspell.git@c956c0e97af00ef789afb2f64d02c9a5a50e6eb1', + 'src/third_party/hunspell_dictionaries': + Var('git_url') + '/chromium/deps/hunspell_dictionaries.git@4560bdd463a3500e2334e85c8a0e9e5d5d6774e7', + 'src/third_party/icu': + Var('git_url') + '/chromium/deps/icu52.git@dd727641e190d60e4593bcb3a35c7f51eb4925c5', + 'src/third_party/jsoncpp/source/include': + Var('git_url') + '/external/jsoncpp/jsoncpp/include.git@b0dd48e02b6e6248328db78a65b5c601f150c349', + 'src/third_party/jsoncpp/source/src/lib_json': + Var('git_url') + '/external/jsoncpp/jsoncpp/src/lib_json.git@a8caa51ba2f80971a45880425bf2ae864a786784', + 'src/third_party/leveldatabase/src': + Var('git_url') + '/external/leveldb.git@3f77584eb3f9754bbb7079070873ece3f30a1e6b', + 'src/third_party/libaddressinput/src': + Var('git_url') + '/external/libaddressinput.git@51f43544159ce5e2d4e19dfa1673149ba73a0200', + 'src/third_party/libc++/trunk': + Var('git_url') + '/chromium/llvm-project/libcxx.git@48198f9110397fff47fe7c37cbfa296be7d44d3d', + 'src/third_party/libc++abi/trunk': + Var('git_url') + '/chromium/llvm-project/libcxxabi.git@4ad1009ab3a59fa7a6896d74d5e4de5885697f95', + 'src/third_party/libexif/sources': + Var('git_url') + '/chromium/deps/libexif/sources.git@ed98343daabd7b4497f97fda972e132e6877c48a', + 'src/third_party/libjingle/source/talk': + Var('git_url') + '/external/webrtc/trunk/talk.git@f97800413f157c911aefbf5be167dbd4806a2323', + 'src/third_party/libjpeg_turbo': + Var('git_url') + '/chromium/deps/libjpeg_turbo.git@034e9a9747e0983bc19808ea70e469bc8342081f', + 'src/third_party/libphonenumber/src/phonenumbers': + Var('git_url') + '/external/libphonenumber/cpp/src/phonenumbers.git@8d8b5b3b2035197795d27573d4cf566b5d9ad689', + 'src/third_party/libphonenumber/src/resources': + Var('git_url') + '/external/libphonenumber/resources.git@de095548d2ae828a414e01f3951bfefba902b4e4', + 'src/third_party/libphonenumber/src/test': + Var('git_url') + '/external/libphonenumber/cpp/test.git@883b7b86541d64b2691f7c0e65facb0b08db73e8', + 'src/third_party/libsrtp': + Var('git_url') + '/chromium/deps/libsrtp.git@6446144c7f083552f21cc4e6768e891bcb767574', + 'src/third_party/libvpx': + Var('git_url') + '/chromium/deps/libvpx.git@2e5ced5fd62a73f4f5687ab19520b3aad1c53f6f', + 'src/third_party/libwebm/source': + Var('git_url') + '/webm/libwebm.git@0d4cb404ea4195e5e21d04db2c955615535ce62e', + 'src/third_party/libyuv': + Var('git_url') + '/external/libyuv.git@5a09c3ef2aa3e6b6da4007746fdde04ca56dae7c', + 'src/third_party/mesa/src': + Var('git_url') + '/chromium/deps/mesa.git@9731cb962963bca8a05f3d0f6ea40c3a781f0537', + 'src/third_party/openmax_dl': + Var('git_url') + '/external/webrtc/deps/third_party/openmax.git@01642706d2b37cb7b9db84add870ea0fdabdf5ad', + 'src/third_party/opus/src': + Var('git_url') + '/chromium/deps/opus.git@cae696156f1e60006e39821e79a1811ae1933c69', + 'src/third_party/ots': + Var('git_url') + '/external/ots.git@98897009f3ea8a5fa3e20a4a74977da7aaa8e61a', + 'src/third_party/pdfium': + 'https://pdfium.googlesource.com/pdfium.git@4dc95e74e1acc75f4eab08bc771874cd2a9c3a9b', + 'src/third_party/py_trace_event/src': + Var('git_url') + '/external/py_trace_event.git@dd463ea9e2c430de2b9e53dea57a77b4c3ac9b30', + 'src/third_party/pyftpdlib/src': + Var('git_url') + '/external/pyftpdlib.git@2be6d65e31c7ee6320d059f581f05ae8d89d7e45', + 'src/third_party/pywebsocket/src': + Var('git_url') + '/external/pywebsocket/src.git@cb349e87ddb30ff8d1fa1a89be39cec901f4a29c', + 'src/third_party/safe_browsing/testing': + Var('git_url') + '/external/google-safe-browsing/testing.git@9d7e8064f3ca2e45891470c9b5b1dce54af6a9d6', + 'src/third_party/scons-2.0.1': + Var('git_url') + '/native_client/src/third_party/scons-2.0.1.git@1c1550e17fc26355d08627fbdec13d8291227067', + 'src/third_party/sfntly/cpp/src': + Var('git_url') + '/external/sfntly/cpp/src.git@1bdaae8fc788a5ac8936d68bf24f37d977a13dac', + 'src/third_party/skia': + Var('git_url') + '/skia.git@2e74f758f8379338f75898f28128ade1dfcf3702', + 'src/third_party/smhasher/src': + Var('git_url') + '/external/smhasher.git@e87738e57558e0ec472b2fc3a643b838e5b6e88f', + 'src/third_party/snappy/src': + Var('git_url') + '/external/snappy.git@762bb32f0c9d2f31ba4958c7c0933d22e80c20bf', + 'src/third_party/swig/Lib': + Var('git_url') + '/chromium/deps/swig/Lib.git@f2a695d52e61e6a8d967731434f165ed400f0d69', + 'src/third_party/trace-viewer': + Var('git_url') + '/external/trace-viewer.git@c3820e9a59e1d2869a7848c4a65cb7aed08b915d', + 'src/third_party/usrsctp/usrsctplib': + Var('git_url') + '/external/usrsctplib.git@190c8cbfcf8fd810aa09e0fab4ca62a8ce724e14', + 'src/third_party/webdriver/pylib': + Var('git_url') + '/external/selenium/py.git@5fd78261a75fe08d27ca4835fb6c5ce4b42275bd', + 'src/third_party/webgl/src': + Var('git_url') + '/external/khronosgroup/webgl.git@152f156d821aeeb688d0979daa529cdad44c0bc7', + 'src/third_party/webpagereplay': + Var('git_url') + '/external/web-page-replay.git@2f7b704b8b567983c040f555d3e46f9766db8e87', + 'src/third_party/webrtc': + Var('git_url') + '/external/webrtc/trunk/webrtc.git@71616dbb8cdd3ea13e0a964d18456ca3fe002dab', + 'src/third_party/yasm/source/patched-yasm': + Var('git_url') + '/chromium/deps/yasm/patched-yasm.git@c960eb11ccda80b10ed50be39df4f0663b371d1d', + 'src/tools/deps2git': + Var('git_url') + '/chromium/tools/deps2git.git@f04828eb0b5acd3e7ad983c024870f17f17b06d9', + 'src/tools/grit': + Var('git_url') + '/external/grit-i18n.git@a24a0e647bb718b3540db89864cf586b12331e82', + 'src/tools/gyp': + Var('git_url') + '/external/gyp.git@487c0b6ae8b44932e45347211bca0e8387718436', + 'src/tools/page_cycler/acid3': + Var('git_url') + '/chromium/deps/acid3.git@6be0a66a1ebd7ebc5abc1b2f405a945f6d871521', + 'src/tools/swarming_client': + Var('git_url') + '/external/swarming.client.git@1f8ba359e84dc7f26b1ba286dfb4e28674efbff4', + 'src/v8': + Var('git_url') + '/v8/v8.git@d2f16971bdcc2899e0939815005f43253e3e7410', +} + +deps_os = { + 'android': + { + 'src/pdf': + None, + 'src/third_party/android_protobuf/src': + Var('git_url') + '/external/android_protobuf.git@94f522f907e3f34f70d9e7816b947e62fddbb267', + 'src/third_party/android_tools': + Var('git_url') + '/android_tools.git@4c47ef63519d579b9ac029fcb6dcc81e38d82984', + 'src/third_party/android_webview_glue/src': + Var('git_url') + '/external/android_webview_glue.git@7d62eab4ca242beacac4471c002e998ef5c218b8', + 'src/third_party/apache-mime4j': + Var('git_url') + '/chromium/deps/apache-mime4j.git@28cb1108bff4b6cf0a2e86ff58b3d025934ebe3a', + 'src/third_party/elfutils/src': + Var('git_url') + '/external/elfutils.git@249673729a7e5dbd5de4f3760bdcaa3d23d154d7', + 'src/third_party/eyesfree/src/android/java/src/com/googlecode/eyesfree/braille': + Var('git_url') + '/external/eyes-free/braille/client/src/com/googlecode/eyesfree/braille.git@77bf6edb0138e3a38a2772248696f130dab45e34', + 'src/third_party/findbugs': + Var('git_url') + '/chromium/deps/findbugs.git@7f69fa78a6db6dc31866d09572a0e356e921bf12', + 'src/third_party/freetype': + Var('git_url') + '/chromium/src/third_party/freetype.git@a2b9955b49034a51dfbc8bf9f4e9d312149cecac', + 'src/third_party/httpcomponents-client': + Var('git_url') + '/chromium/deps/httpcomponents-client.git@285c4dafc5de0e853fa845dce5773e223219601c', + 'src/third_party/httpcomponents-core': + Var('git_url') + '/chromium/deps/httpcomponents-core.git@9f7180a96f8fa5cab23f793c14b413356d419e62', + 'src/third_party/jarjar': + Var('git_url') + '/chromium/deps/jarjar.git@2e1ead4c68c450e0b77fe49e3f9137842b8b6920', + 'src/third_party/jsr-305/src': + Var('git_url') + '/external/jsr-305.git@642c508235471f7220af6d5df2d3210e3bfc0919', + 'src/third_party/junit/src': + Var('git_url') + '/external/junit.git@c62e2df8dbecccb1b434d4ba8843b59e90b03266', + 'src/third_party/lss': + Var('git_url') + '/external/linux-syscall-support/lss.git@952107fa7cea0daaabead28c0e92d579bee517eb', + }, + 'ios': + { + 'src/chrome/test/data/perf/canvas_bench': + None, + 'src/chrome/test/data/perf/frame_rate/content': + None, + 'src/native_client': + None, + 'src/testing/iossim/third_party/class-dump': + Var('git_url') + '/chromium/deps/class-dump.git@89bd40883c767584240b4dade8b74e6f57b9bdab', + 'src/third_party/cld_2/src': + None, + 'src/third_party/ffmpeg': + None, + 'src/third_party/google_toolbox_for_mac/src': + Var('git_url') + '/external/google-toolbox-for-mac.git@a09526298f9dd1ec49d3b3ac5608d2a257b94cef', + 'src/third_party/hunspell': + None, + 'src/third_party/hunspell_dictionaries': + None, + 'src/third_party/nss': + Var('git_url') + '/chromium/deps/nss.git@a4192054ee0a9902ec81e53bc7a5c2ea2991d764', + 'src/third_party/webgl': + None, + }, + 'mac': + { + 'src/chrome/installer/mac/third_party/xz/xz': + Var('git_url') + '/chromium/deps/xz.git@eecaf55632ca72e90eb2641376bce7cdbc7284f7', + 'src/chrome/tools/test/reference_build/chrome_mac': + Var('git_url') + '/chromium/reference_builds/chrome_mac.git@8dc181329e7c5255f83b4b85dc2f71498a237955', + 'src/third_party/google_toolbox_for_mac/src': + Var('git_url') + '/external/google-toolbox-for-mac.git@a09526298f9dd1ec49d3b3ac5608d2a257b94cef', + 'src/third_party/lighttpd': + Var('git_url') + '/chromium/deps/lighttpd.git@9dfa55d15937a688a92cbf2b7a8621b0927d06eb', + 'src/third_party/nss': + Var('git_url') + '/chromium/deps/nss.git@a4192054ee0a9902ec81e53bc7a5c2ea2991d764', + 'src/third_party/pdfsqueeze': + Var('git_url') + '/external/pdfsqueeze.git@5936b871e6a087b7e50d4cbcb122378d8a07499f', + 'src/third_party/swig/mac': + Var('git_url') + '/chromium/deps/swig/mac.git@1b182eef16df2b506f1d710b34df65d55c1ac44e', + }, + 'unix': + { + 'build/third_party/cbuildbot_chromite': + Var('git_url') + '/chromiumos/chromite.git@38de38fd79fab228e693a1b22e60e2fa69bf85fd', + 'build/third_party/xvfb': + Var('git_url') + '/chromium/tools/third_party/xvfb.git@aebb1aadf1422e4d81e831e13746b8f7ae322e07', + 'src/chrome/tools/test/reference_build/chrome_linux': + Var('git_url') + '/chromium/reference_builds/chrome_linux64.git@033d053a528e820e1de3e2db766678d862a86b36', + 'src/third_party/chromite': + Var('git_url') + '/chromiumos/chromite.git@dda64836fc8b02ed89fed167603a838007e99712', + 'src/third_party/cros_system_api': + Var('git_url') + '/chromiumos/platform/system_api.git@a21c902a409c2238c0a73a44e8fe11f1ed9535a5', + 'src/third_party/fontconfig/src': + Var('git_url') + '/external/fontconfig.git@f16c3118e25546c1b749f9823c51827a60aeb5c1', + 'src/third_party/freetype2/src': + Var('git_url') + '/chromium/src/third_party/freetype2.git@495a23fce9cd125f715dc20643d14fed226d76ac', + 'src/third_party/liblouis/src': + Var('git_url') + '/external/liblouis-github.git@5f9c03f2a3478561deb6ae4798175094be8a26c2', + 'src/third_party/lss': + Var('git_url') + '/external/linux-syscall-support/lss.git@952107fa7cea0daaabead28c0e92d579bee517eb', + 'src/third_party/pyelftools': + Var('git_url') + '/chromiumos/third_party/pyelftools.git@bdc1d380acd88d4bfaf47265008091483b0d614e', + 'src/third_party/swig/linux': + Var('git_url') + '/chromium/deps/swig/linux.git@866b8e0e0e0cfe99ebe608260030916ca0c3f92d', + 'src/third_party/undoview': + Var('git_url') + '/chromium/deps/undoview.git@3ba503e248f3cdbd81b78325a24ece0984637559', + 'src/third_party/xdg-utils': + Var('git_url') + '/chromium/deps/xdg-utils.git@d80274d5869b17b8c9067a1022e4416ee7ed5e0d', + }, + 'win': + { + 'src/chrome/tools/test/reference_build/chrome_win': + Var('git_url') + '/chromium/reference_builds/chrome_win.git@f8a3a845dfc845df6b14280f04f86a61959357ef', + 'src/third_party/bison': + Var('git_url') + '/chromium/deps/bison.git@083c9a45e4affdd5464ee2b224c2df649c6e26c3', + 'src/third_party/cygwin': + Var('git_url') + '/chromium/deps/cygwin.git@c89e446b273697fadf3a10ff1007a97c0b7de6df', + 'src/third_party/gnu_binutils': + Var('git_url') + '/native_client/deps/third_party/gnu_binutils.git@f4003433b61b25666565690caf3d7a7a1a4ec436', + 'src/third_party/gperf': + Var('git_url') + '/chromium/deps/gperf.git@d892d79f64f9449770443fb06da49b5a1e5d33c1', + 'src/third_party/lighttpd': + Var('git_url') + '/chromium/deps/lighttpd.git@9dfa55d15937a688a92cbf2b7a8621b0927d06eb', + 'src/third_party/mingw-w64/mingw/bin': + Var('git_url') + '/native_client/deps/third_party/mingw-w64/mingw/bin.git@3cc8b140b883a9fe4986d12cfd46c16a093d3527', + 'src/third_party/nacl_sdk_binaries': + Var('git_url') + '/chromium/deps/nacl_sdk_binaries.git@759dfca03bdc774da7ecbf974f6e2b84f43699a5', + 'src/third_party/nss': + Var('git_url') + '/chromium/deps/nss.git@a4192054ee0a9902ec81e53bc7a5c2ea2991d764', + 'src/third_party/omaha/src/omaha': + Var('git_url') + '/external/omaha.git@098c7a3d157218dab4eed595e8f2fbe5a20a0bae', + 'src/third_party/pefile': + Var('git_url') + '/external/pefile.git@72c6ae42396cb913bcab63c15585dc3b5c3f92f1', + 'src/third_party/perl': + Var('git_url') + '/chromium/deps/perl.git@ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78', + 'src/third_party/psyco_win32': + Var('git_url') + '/chromium/deps/psyco_win32.git@f5af9f6910ee5a8075bbaeed0591469f1661d868', + 'src/third_party/swig/win': + Var('git_url') + '/chromium/deps/swig/win.git@986f013ba518541adf5c839811efb35630a31031', + 'src/third_party/yasm/binaries': + Var('git_url') + '/chromium/deps/yasm/binaries.git@52f9b3f4b0aa06da24ef8b123058bb61ee468881', + }, +} + +include_rules = [ + '+base', + '+build', + '+ipc', + '+library_loaders', + '+testing', + '+third_party/icu/source/common/unicode', + '+third_party/icu/source/i18n/unicode', + '+url' +] + +skip_child_includes = [ + 'breakpad', + 'delegate_execute', + 'metro_driver', + 'native_client_sdk', + 'o3d', + 'sdch', + 'skia', + 'testing', + 'third_party', + 'v8', + 'win8' +] + +hooks = [ + { + 'action': + [ + 'python', + 'src/build/landmines.py' +], + 'pattern': + '.', + 'name': + 'landmines' +}, + { + 'action': + [ + 'python', + 'src/build/download_nacl_toolchains.py', + '--exclude', + 'arm_trusted' +], + 'pattern': + '.', + 'name': + 'nacltools' +}, + { + 'action': + [ + 'python', + 'src/chrome/installer/linux/sysroot_scripts/install-debian.wheezy.sysroot.py', + '--linux-only', + '--arch=amd64' +], + 'pattern': + '.', + 'name': + 'sysroot' +}, + { + 'action': + [ + 'python', + 'src/chrome/installer/linux/sysroot_scripts/install-debian.wheezy.sysroot.py', + '--linux-only', + '--arch=i386' +], + 'pattern': + '.', + 'name': + 'sysroot' +}, + { + 'action': + [ + 'python', + 'src/chrome/installer/linux/sysroot_scripts/install-debian.wheezy.sysroot.py', + '--linux-only', + '--arch=arm' +], + 'pattern': + '.', + 'name': + 'sysroot' +}, + { + 'action': + [ + 'python', + 'src/build/vs_toolchain.py', + 'update' +], + 'pattern': + '.', + 'name': + 'win_toolchain' +}, + { + 'action': + [ + 'python', + 'src/tools/clang/scripts/update.py', + '--if-needed' +], + 'pattern': + '.', + 'name': + 'clang' +}, + { + 'action': + [ + 'python', + 'src/build/util/lastchange.py', + '-o', + 'src/build/util/LASTCHANGE' +], + 'pattern': + '.', + 'name': + 'lastchange' +}, + { + 'action': + [ + 'python', + 'src/build/util/lastchange.py', + '-s', + 'src/third_party/WebKit', + '-o', + 'src/build/util/LASTCHANGE.blink' +], + 'pattern': + '.', + 'name': + 'lastchange' +}, + { + 'action': + [ + 'download_from_google_storage', + '--no_resume', + '--platform=win32', + '--no_auth', + '--bucket', + 'chromium-gn', + '-s', + 'src/buildtools/win/gn.exe.sha1' +], + 'pattern': + '.', + 'name': + 'gn_win' +}, + { + 'action': + [ + 'download_from_google_storage', + '--no_resume', + '--platform=darwin', + '--no_auth', + '--bucket', + 'chromium-gn', + '-s', + 'src/buildtools/mac/gn.sha1' +], + 'pattern': + '.', + 'name': + 'gn_mac' +}, + { + 'action': + [ + 'download_from_google_storage', + '--no_resume', + '--platform=linux*', + '--no_auth', + '--bucket', + 'chromium-gn', + '-s', + 'src/buildtools/linux32/gn.sha1' +], + 'pattern': + '.', + 'name': + 'gn_linux32' +}, + { + 'action': + [ + 'download_from_google_storage', + '--no_resume', + '--platform=linux*', + '--no_auth', + '--bucket', + 'chromium-gn', + '-s', + 'src/buildtools/linux64/gn.sha1' +], + 'pattern': + '.', + 'name': + 'gn_linux64' +}, + { + 'action': + [ + 'download_from_google_storage', + '--no_resume', + '--platform=win32', + '--no_auth', + '--bucket', + 'chromium-clang-format', + '-s', + 'src/buildtools/win/clang-format.exe.sha1' +], + 'pattern': + '.', + 'name': + 'clang_format_win' +}, + { + 'action': + [ + 'download_from_google_storage', + '--no_resume', + '--platform=darwin', + '--no_auth', + '--bucket', + 'chromium-clang-format', + '-s', + 'src/buildtools/mac/clang-format.sha1' +], + 'pattern': + '.', + 'name': + 'clang_format_mac' +}, + { + 'action': + [ + 'download_from_google_storage', + '--no_resume', + '--platform=linux*', + '--no_auth', + '--bucket', + 'chromium-clang-format', + '-s', + 'src/buildtools/linux64/clang-format.sha1' +], + 'pattern': + '.', + 'name': + 'clang_format_linux' +}, + { + 'action': + [ + 'python', + 'src/third_party/binutils/download.py' +], + 'pattern': + 'src/third_party/binutils', + 'name': + 'binutils' +}, + { + 'action': + [ + 'download_from_google_storage', + '--no_resume', + '--platform=linux*', + '--no_auth', + '--bucket', + 'chromium-eu-strip', + '-s', + 'src/build/linux/bin/eu-strip.sha1' +], + 'pattern': + '.', + 'name': + 'eu-strip' +}, + { + 'action': + [ + 'download_from_google_storage', + '--no_resume', + '--platform=win32', + '--no_auth', + '--bucket', + 'chromium-drmemory', + '-s', + 'src/third_party/drmemory/drmemory-windows-sfx.exe.sha1' +], + 'pattern': + '.', + 'name': + 'drmemory' +}, + { + 'action': + [ + 'python', + 'src/build/get_syzygy_binaries.py', + '--output-dir=src/third_party/syzygy/binaries', + '--revision=52a58e8bb19c5dcc97970bae4b8c00c5891f3568', + '--overwrite' +], + 'pattern': + '.', + 'name': + 'syzygy-binaries' +}, + { + 'action': + [ + 'download_from_google_storage', + '--no_resume', + '--platform=win32', + '--directory', + '--recursive', + '--no_auth', + '--num_threads=16', + '--bucket', + 'chromium-apache-win32', + 'src/third_party/apache-win32' +], + 'pattern': + '\\.sha1', + 'name': + 'apache_win32' +}, + { + 'action': + [ + 'python', + 'src/build/gyp_chromium' +], + 'pattern': + '.', + 'name': + 'gyp' +}, + { + 'action': + [ + 'python', + 'src/tools/check_git_config.py', + '--running-as-hook' +], + 'pattern': + '.', + 'name': + 'check_git_config' +}, + { + 'action': + [ + 'python', + 'src/tools/remove_stale_pyc_files.py', + 'src/tools' +], + 'pattern': + 'src/tools/.*\\.py', + 'name': + 'remove_stale_pyc_files' +} +] diff --git a/.gitignore b/.gitignore index 2f71dc36540e2..c1bf2f6304d17 100644 --- a/.gitignore +++ b/.gitignore @@ -218,6 +218,7 @@ v8.log /net/testserver.log /out /out_* +/ozone /ppapi/native_client/nacl_irt.xml /ppapi/native_client/ppapi_lib.xml /ppapi/native_client/src/trusted/plugin/ppGoogleNaClPluginChrome.xml @@ -308,6 +309,7 @@ v8.log /third_party/jsr-305/src /third_party/junit/src /third_party/khronos_glcts +/third_party/khronos/CL /third_party/leveldatabase/src /third_party/leveldb /third_party/libaddressinput/src @@ -377,6 +379,7 @@ v8.log /third_party/v8-i18n /third_party/valgrind /third_party/v4l2capture +/third_party/webcl /third_party/webdriver/pylib /third_party/webdriver/python/selenium /third_party/webgl @@ -434,3 +437,4 @@ v8.log /win8/metro_driver/metro_driver_version_resources.xml /x86-generic_out/ /xcodebuild +/xwalk diff --git a/DEPS b/DEPS index a896bfb4a6a08..760a9546d9eea 100644 --- a/DEPS +++ b/DEPS @@ -1,783 +1,685 @@ -# This file is used to manage the dependencies of the Chromium src repo. It is -# used by gclient to determine what version of each dependency to check out, and -# where. -# -# For more information, please refer to the official documentation: -# https://sites.google.com/a/chromium.org/dev/developers/how-tos/get-the-code -# -# When adding a new dependency, please update the top-level .gitignore file -# to list the dependency's destination directory. -# -# ----------------------------------------------------------------------------- -# Rolling deps -# ----------------------------------------------------------------------------- -# All repositories in this file are git-based, using Chromium git mirrors where -# necessary (e.g., a git mirror is used when the source project is SVN-based). -# To update the revision that Chromium pulls for a given dependency: -# -# # Create and switch to a new branch -# git new-branch depsroll -# # Run roll-dep (provided by depot_tools) giving the dep's path and the -# # desired SVN revision number (e.g., third_party/foo/bar and a revision such -# # number from Subversion) -# roll-dep third_party/foo/bar REVISION_NUMBER -# # You should now have a modified DEPS file; commit and upload as normal -# git commit -a -# git cl upload - - -vars = { - # Use this googlecode_url variable only if there is an internal mirror for it. - # If you do not know, use the full path while defining your new deps entry. - 'googlecode_url': 'http://%s.googlecode.com/svn', - 'sourceforge_url': 'http://svn.code.sf.net/p/%(repo)s/code', - 'llvm_url': 'http://src.chromium.org/llvm-project', - 'llvm_git': 'https://llvm.googlesource.com', - 'libcxx_revision': '48198f9110397fff47fe7c37cbfa296be7d44d3d', - 'libcxxabi_revision': '4ad1009ab3a59fa7a6896d74d5e4de5885697f95', - 'webkit_trunk': 'http://src.chromium.org/blink/trunk', - 'webkit_revision': '33445762977cec86f2fff85da34f01ca132858fa', # from svn revision 184994 - 'chromium_git': 'https://chromium.googlesource.com', - 'chromiumos_git': 'https://chromium.googlesource.com/chromiumos', - 'pdfium_git': 'https://pdfium.googlesource.com', - 'skia_git': 'https://skia.googlesource.com', - 'boringssl_git': 'https://boringssl.googlesource.com', - 'libvpx_revision': '2e5ced5fd62a73f4f5687ab19520b3aad1c53f6f', - 'sfntly_revision': '1bdaae8fc788a5ac8936d68bf24f37d977a13dac', - 'skia_revision': '2ecf86e55ecb893cf4d04e16a4ac5b0de6dcf173', - # 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': '731b3e5a9965e4fd3118dc9c882fd89cd5308204', # from svn revision 25122 - # Three lines of non-changing comments so that - # the commit queue can handle CLs rolling WebRTC - # and V8 without interference from each other. - # Three lines of non-changing comments so that - # the commit queue can handle CLs rolling swarming_client - # and whatever else without interference from each other. - 'swarming_revision': '1f8ba359e84dc7f26b1ba286dfb4e28674efbff4', - # Three lines of non-changing comments so that - # the commit queue can handle CLs rolling ANGLE - # and whatever else without interference from each other. - "angle_revision": "4de44cb67e9e36966fb1993c0be35659a47182ef", - # Three lines of non-changing comments so that - # the commit queue can handle CLs rolling build tools - # and whatever else without interference from each other. - 'buildtools_revision': 'c27f95bd1d9baaef70c879dea375090dd1496147', - # 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': '4dc95e74e1acc75f4eab08bc771874cd2a9c3a9b', - # Three lines of non-changing comments so that - # the commit queue can handle CLs rolling openmax_dl - # and whatever else without interference from each other. - 'openmax_dl_revision': '01642706d2b37cb7b9db84add870ea0fdabdf5ad', - # Three lines of non-changing comments so that - # the commit queue can handle CLs rolling BoringSSL - # and whatever else without interference from each other. - 'boringssl_revision': '817ec3462e246b8301a73e44854e2bb3df90d5e6', - # 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': 'a4192054ee0a9902ec81e53bc7a5c2ea2991d764', - # 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. - 'google_toolbox_for_mac_revision': 'a09526298f9dd1ec49d3b3ac5608d2a257b94cef', - # Three lines of non-changing comments so that - # the commit queue can handle CLs rolling lighttpd - # and whatever else without interference from each other. - 'lighttpd_revision': '9dfa55d15937a688a92cbf2b7a8621b0927d06eb', - # Three lines of non-changing comments so that - # the commit queue can handle CLs rolling lss - # and whatever else without interference from each other. - 'lss_revision': '952107fa7cea0daaabead28c0e92d579bee517eb', - # Three lines of non-changing comments so that - # the commit queue can handle CLs rolling NaCl - # and whatever else without interference from each other. - 'nacl_revision': '9cd80947288ebca86dd07b55171089b84553a7c7', # from svn revision r14043 -} - -# Only these hosts are allowed for dependencies in this DEPS file. -# If you need to add a new host, contact chrome infrastracture team. -allowed_hosts = [ - 'chromium.googlesource.com', - 'boringssl.googlesource.com', - 'pdfium.googlesource.com', -] - -deps = { - 'src/breakpad/src': - Var('chromium_git') + '/external/google-breakpad/src.git' + '@' + 'f37b59821ecbd69c54f3388026d2e98cd8b2fba2', # from svn revision 1397 - - 'src/buildtools': - Var('chromium_git') + '/chromium/buildtools.git' + '@' + Var('buildtools_revision'), - - 'src/sdch/open-vcdiff': - Var('chromium_git') + '/external/open-vcdiff.git' + '@' + '438f2a5be6d809bc21611a94cd37bfc8c28ceb33', # from svn revision 41 - - 'src/testing/gtest': - Var('chromium_git') + '/external/googletest.git' + '@' + '4650552ff637bb44ecf7784060091cbed3252211', # from svn revision 692 - - 'src/testing/gmock': - Var('chromium_git') + '/external/googlemock.git' + '@' + '896ba0e03f520fb9b6ed582bde2bd00847e3c3f2', # from svn revision 485 - - 'src/third_party/angle': - Var('chromium_git') + '/angle/angle.git' + '@' + Var('angle_revision'), - - 'src/third_party/colorama/src': - Var('chromium_git') + '/external/colorama.git' + '@' + '799604a1041e9b3bc5d2789ecbd7e8db2e18e6b8', - - 'src/third_party/trace-viewer': - Var('chromium_git') + '/external/trace-viewer.git' + '@' + 'c3820e9a59e1d2869a7848c4a65cb7aed08b915d', - - 'src/third_party/WebKit': - Var('chromium_git') + '/chromium/blink.git' + '@' + Var('webkit_revision'), - - 'src/third_party/icu': - Var('chromium_git') + '/chromium/deps/icu52.git' + '@' + 'd8b2a9d7b0039a4950ee008c5b1d998902c44c60', # from svn revision 292476 - - 'src/third_party/libexif/sources': - Var('chromium_git') + '/chromium/deps/libexif/sources.git' + '@' + 'ed98343daabd7b4497f97fda972e132e6877c48a', - - 'src/third_party/hunspell': - Var('chromium_git') + '/chromium/deps/hunspell.git' + '@' + 'c956c0e97af00ef789afb2f64d02c9a5a50e6eb1', - - 'src/third_party/hunspell_dictionaries': - Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + '4560bdd463a3500e2334e85c8a0e9e5d5d6774e7', - - 'src/third_party/safe_browsing/testing': - Var('chromium_git') + '/external/google-safe-browsing/testing.git' + '@' + '9d7e8064f3ca2e45891470c9b5b1dce54af6a9d6', - - 'src/third_party/cacheinvalidation/src': - Var('chromium_git') + '/external/google-cache-invalidation-api/src.git' + '@' + 'c91bd9d9fed06bf440be64f87b94a2effdb32bc4', # from svn revision 341 - - 'src/third_party/leveldatabase/src': - Var('chromium_git') + '/external/leveldb.git' + '@' + '3f77584eb3f9754bbb7079070873ece3f30a1e6b', - - 'src/third_party/libc++/trunk': - Var('chromium_git') + '/chromium/llvm-project/libcxx.git' + '@' + Var('libcxx_revision'), - - 'src/third_party/libc++abi/trunk': - Var('chromium_git') + '/chromium/llvm-project/libcxxabi.git' + '@' + Var('libcxxabi_revision'), - - 'src/third_party/snappy/src': - Var('chromium_git') + '/external/snappy.git' + '@' + '762bb32f0c9d2f31ba4958c7c0933d22e80c20bf', - - 'src/tools/grit': - Var('chromium_git') + '/external/grit-i18n.git' + '@' + 'a24a0e647bb718b3540db89864cf586b12331e82', # from svn revision 182 - - 'src/tools/gyp': - Var('chromium_git') + '/external/gyp.git' + '@' + '487c0b6ae8b44932e45347211bca0e8387718436', # from svn revision 1998 - - 'src/tools/swarming_client': - Var('chromium_git') + '/external/swarming.client.git' + '@' + Var('swarming_revision'), - - 'src/v8': - Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), - - 'src/native_client': - Var('chromium_git') + '/native_client/src/native_client.git' + '@' + Var('nacl_revision'), - - 'src/third_party/sfntly/cpp/src': - Var('chromium_git') + '/external/sfntly/cpp/src.git' + '@' + Var('sfntly_revision'), - - 'src/third_party/skia': - Var('chromium_git') + '/skia.git' + '@' + Var('skia_revision'), - - 'src/third_party/ots': - Var('chromium_git') + '/external/ots.git' + '@' + '98897009f3ea8a5fa3e20a4a74977da7aaa8e61a', - - 'src/third_party/brotli/src': - Var('chromium_git') + '/external/font-compression-reference.git' + '@' + '65cb3326e30ef8a67eb1d4411ec563e91be6e9ae', - - 'src/tools/page_cycler/acid3': - Var('chromium_git') + '/chromium/deps/acid3.git' + '@' + '6be0a66a1ebd7ebc5abc1b2f405a945f6d871521', - - 'src/chrome/test/data/perf/canvas_bench': - Var('chromium_git') + '/chromium/canvas_bench.git' + '@' + 'a7b40ea5ae0239517d78845a5fc9b12976bfc732', - - 'src/chrome/test/data/perf/frame_rate/content': - Var('chromium_git') + '/chromium/frame_rate/content.git' + '@' + 'c10272c88463efeef6bb19c9ec07c42bc8fe22b9', - - 'src/third_party/bidichecker': - Var('chromium_git') + '/external/bidichecker/lib.git' + '@' + '97f2aa645b74c28c57eca56992235c79850fa9e0', - - 'src/third_party/webgl/src': - Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '152f156d821aeeb688d0979daa529cdad44c0bc7', - - 'src/third_party/swig/Lib': - Var('chromium_git') + '/chromium/deps/swig/Lib.git' + '@' + 'f2a695d52e61e6a8d967731434f165ed400f0d69', - - 'src/third_party/webdriver/pylib': - Var('chromium_git') + '/external/selenium/py.git' + '@' + '5fd78261a75fe08d27ca4835fb6c5ce4b42275bd', - - 'src/third_party/libvpx': - Var('chromium_git') + '/chromium/deps/libvpx.git' + '@' + Var('libvpx_revision'), - - 'src/third_party/ffmpeg': - Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '399d38b9baba60763e1db26be5d6a8577a4276f4', - - 'src/third_party/libjingle/source/talk': - Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + 'f97800413f157c911aefbf5be167dbd4806a2323', # from svn revision 7662 - - 'src/third_party/usrsctp/usrsctplib': - Var('chromium_git') + '/external/usrsctplib.git' + '@' + '190c8cbfcf8fd810aa09e0fab4ca62a8ce724e14', - - 'src/third_party/libsrtp': - Var('chromium_git') + '/chromium/deps/libsrtp.git' + '@' + '6446144c7f083552f21cc4e6768e891bcb767574', - - 'src/third_party/yasm/source/patched-yasm': - Var('chromium_git') + '/chromium/deps/yasm/patched-yasm.git' + '@' + 'c960eb11ccda80b10ed50be39df4f0663b371d1d', - - 'src/third_party/libjpeg_turbo': - Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + '034e9a9747e0983bc19808ea70e469bc8342081f', - - 'src/third_party/flac': - Var('chromium_git') + '/chromium/deps/flac.git' + '@' + '0635a091379d9677f1ddde5f2eec85d0f096f219', - - 'src/third_party/pyftpdlib/src': - Var('chromium_git') + '/external/pyftpdlib.git' + '@' + '2be6d65e31c7ee6320d059f581f05ae8d89d7e45', - - 'src/third_party/scons-2.0.1': - 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' + '@' + '60ab669c4c545b328b5c8b0453eb2cdecf851651', # from svn revision 7660 - - 'src/third_party/openmax_dl': - Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' + Var('openmax_dl_revision'), - - 'src/third_party/jsoncpp/source/include': - Var('chromium_git') + '/external/jsoncpp/jsoncpp/include.git' + '@' + 'b0dd48e02b6e6248328db78a65b5c601f150c349', - - 'src/third_party/jsoncpp/source/src/lib_json': - Var('chromium_git') + '/external/jsoncpp/jsoncpp/src/lib_json.git' + '@' + 'a8caa51ba2f80971a45880425bf2ae864a786784', - - 'src/third_party/libyuv': - Var('chromium_git') + '/external/libyuv.git' + '@' + '5a09c3ef2aa3e6b6da4007746fdde04ca56dae7c', # from svn revision 1130 - - 'src/third_party/smhasher/src': - Var('chromium_git') + '/external/smhasher.git' + '@' + 'e87738e57558e0ec472b2fc3a643b838e5b6e88f', - - 'src/third_party/libaddressinput/src': - Var('chromium_git') + '/external/libaddressinput.git' + '@' + '51f43544159ce5e2d4e19dfa1673149ba73a0200', - - 'src/third_party/libphonenumber/src/phonenumbers': - Var('chromium_git') + '/external/libphonenumber/cpp/src/phonenumbers.git' + '@' + '8d8b5b3b2035197795d27573d4cf566b5d9ad689', - 'src/third_party/libphonenumber/src/test': - Var('chromium_git') + '/external/libphonenumber/cpp/test.git' + '@' + '883b7b86541d64b2691f7c0e65facb0b08db73e8', - 'src/third_party/libphonenumber/src/resources': - Var('chromium_git') + '/external/libphonenumber/resources.git' + '@' + 'de095548d2ae828a414e01f3951bfefba902b4e4', - - 'src/tools/deps2git': - Var('chromium_git') + '/chromium/tools/deps2git.git' + '@' + 'f04828eb0b5acd3e7ad983c024870f17f17b06d9', - - 'src/third_party/webpagereplay': - Var('chromium_git') + '/external/web-page-replay.git' + '@' + '2f7b704b8b567983c040f555d3e46f9766db8e87', - - 'src/third_party/pywebsocket/src': - Var('chromium_git') + '/external/pywebsocket/src.git' + '@' + 'cb349e87ddb30ff8d1fa1a89be39cec901f4a29c', - - 'src/third_party/opus/src': - Var('chromium_git') + '/chromium/deps/opus.git' + '@' + 'cae696156f1e60006e39821e79a1811ae1933c69', - - 'src/media/cdm/ppapi/api': - Var('chromium_git') + '/chromium/cdm.git' + '@' + 'f924b6382b05c57677455ac40f210b33809591ef', # from svn revision 292736 - - 'src/third_party/mesa/src': - Var('chromium_git') + '/chromium/deps/mesa.git' + '@' + '9731cb962963bca8a05f3d0f6ea40c3a781f0537', - - 'src/third_party/cld_2/src': - Var('chromium_git') + '/external/cld2.git' + '@' + '14d9ef8d4766326f8aa7de54402d1b9c782d4481', # from svn revision 193 - - 'src/chrome/browser/resources/pdf/html_office': - Var('chromium_git') + '/chromium/html-office-public.git' + '@' + 'eeff97614f65e0578529490d44d412032c3d7359', - - 'src/third_party/libwebm/source': - Var('chromium_git') + '/webm/libwebm.git' + '@' + '0d4cb404ea4195e5e21d04db2c955615535ce62e', - - 'src/third_party/pdfium': - 'https://pdfium.googlesource.com/pdfium.git' + '@' + Var('pdfium_revision'), - - 'src/third_party/boringssl/src': - 'https://boringssl.googlesource.com/boringssl.git' + '@' + Var('boringssl_revision'), - - 'src/third_party/py_trace_event/src': - Var('chromium_git') + '/external/py_trace_event.git' + '@' + 'dd463ea9e2c430de2b9e53dea57a77b4c3ac9b30', -} - - -deps_os = { - 'win': { - 'src/chrome/tools/test/reference_build/chrome_win': - Var('chromium_git') + '/chromium/reference_builds/chrome_win.git' + '@' + 'f8a3a845dfc845df6b14280f04f86a61959357ef', - - 'src/third_party/cygwin': - Var('chromium_git') + '/chromium/deps/cygwin.git' + '@' + 'c89e446b273697fadf3a10ff1007a97c0b7de6df', - - 'src/third_party/psyco_win32': - Var('chromium_git') + '/chromium/deps/psyco_win32.git' + '@' + 'f5af9f6910ee5a8075bbaeed0591469f1661d868', - - 'src/third_party/bison': - Var('chromium_git') + '/chromium/deps/bison.git' + '@' + '083c9a45e4affdd5464ee2b224c2df649c6e26c3', - - 'src/third_party/gperf': - Var('chromium_git') + '/chromium/deps/gperf.git' + '@' + 'd892d79f64f9449770443fb06da49b5a1e5d33c1', - - 'src/third_party/perl': - Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78', - - 'src/third_party/lighttpd': - Var('chromium_git') + '/chromium/deps/lighttpd.git' + '@' + Var('lighttpd_revision'), - - # Parses Windows PE/COFF executable format. - 'src/third_party/pefile': - Var('chromium_git') + '/external/pefile.git' + '@' + '72c6ae42396cb913bcab63c15585dc3b5c3f92f1', - - # NSS, for SSLClientSocketNSS. - 'src/third_party/nss': - Var('chromium_git') + '/chromium/deps/nss.git' + '@' + Var('nss_revision'), - - 'src/third_party/swig/win': - Var('chromium_git') + '/chromium/deps/swig/win.git' + '@' + '986f013ba518541adf5c839811efb35630a31031', - - # GNU binutils assembler for x86-32. - 'src/third_party/gnu_binutils': - Var('chromium_git') + '/native_client/deps/third_party/gnu_binutils.git' + '@' + 'f4003433b61b25666565690caf3d7a7a1a4ec436', - # GNU binutils assembler for x86-64. - 'src/third_party/mingw-w64/mingw/bin': - Var('chromium_git') + '/native_client/deps/third_party/mingw-w64/mingw/bin.git' + '@' + '3cc8b140b883a9fe4986d12cfd46c16a093d3527', - - # Dependencies used by libjpeg-turbo - 'src/third_party/yasm/binaries': - Var('chromium_git') + '/chromium/deps/yasm/binaries.git' + '@' + '52f9b3f4b0aa06da24ef8b123058bb61ee468881', - - # Binaries for nacl sdk. - 'src/third_party/nacl_sdk_binaries': - Var('chromium_git') + '/chromium/deps/nacl_sdk_binaries.git' + '@' + '759dfca03bdc774da7ecbf974f6e2b84f43699a5', - - # Omaha code for src/app_installer/. - 'src/third_party/omaha/src/omaha': - Var('chromium_git') + '/external/omaha.git' + '@' + '098c7a3d157218dab4eed595e8f2fbe5a20a0bae', - }, - 'ios': { - 'src/third_party/google_toolbox_for_mac/src': - Var('chromium_git') + '/external/google-toolbox-for-mac.git' + '@' + Var('google_toolbox_for_mac_revision'), - - 'src/third_party/nss': - Var('chromium_git') + '/chromium/deps/nss.git' + '@' + Var('nss_revision'), - - # class-dump utility to generate header files for undocumented SDKs - 'src/testing/iossim/third_party/class-dump': - Var('chromium_git') + '/chromium/deps/class-dump.git' + '@' + '89bd40883c767584240b4dade8b74e6f57b9bdab', - - # Code that's not needed due to not building everything - 'src/chrome/test/data/perf/canvas_bench': None, - 'src/chrome/test/data/perf/frame_rate/content': None, - 'src/native_client': None, - 'src/third_party/cld_2/src': None, - 'src/third_party/ffmpeg': None, - 'src/third_party/hunspell_dictionaries': None, - 'src/third_party/hunspell': None, - 'src/third_party/webgl': None, - }, - 'mac': { - 'src/chrome/tools/test/reference_build/chrome_mac': - Var('chromium_git') + '/chromium/reference_builds/chrome_mac.git' + '@' + '8dc181329e7c5255f83b4b85dc2f71498a237955', - - 'src/third_party/google_toolbox_for_mac/src': - Var('chromium_git') + '/external/google-toolbox-for-mac.git' + '@' + Var('google_toolbox_for_mac_revision'), - - - 'src/third_party/pdfsqueeze': - Var('chromium_git') + '/external/pdfsqueeze.git' + '@' + '5936b871e6a087b7e50d4cbcb122378d8a07499f', - - 'src/third_party/lighttpd': - Var('chromium_git') + '/chromium/deps/lighttpd.git' + '@' + Var('lighttpd_revision'), - - 'src/third_party/swig/mac': - Var('chromium_git') + '/chromium/deps/swig/mac.git' + '@' + '1b182eef16df2b506f1d710b34df65d55c1ac44e', - - # NSS, for SSLClientSocketNSS. - 'src/third_party/nss': - Var('chromium_git') + '/chromium/deps/nss.git' + '@' + Var('nss_revision'), - - 'src/chrome/installer/mac/third_party/xz/xz': - Var('chromium_git') + '/chromium/deps/xz.git' + '@' + 'eecaf55632ca72e90eb2641376bce7cdbc7284f7', - }, - 'unix': { - # Linux, really. - 'src/chrome/tools/test/reference_build/chrome_linux': - Var('chromium_git') + '/chromium/reference_builds/chrome_linux64.git' + '@' + '033d053a528e820e1de3e2db766678d862a86b36', - - 'src/third_party/xdg-utils': - Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d', - - 'src/third_party/swig/linux': - Var('chromium_git') + '/chromium/deps/swig/linux.git' + '@' + '866b8e0e0e0cfe99ebe608260030916ca0c3f92d', - - 'src/third_party/lss': - Var('chromium_git') + '/external/linux-syscall-support/lss.git' + '@' + Var('lss_revision'), - - # For Linux and Chromium OS. - 'src/third_party/cros_system_api': - Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + 'a21c902a409c2238c0a73a44e8fe11f1ed9535a5', - - # Note that this is different from Android's freetype repo. - 'src/third_party/freetype2/src': - Var('chromium_git') + '/chromium/src/third_party/freetype2.git' + '@' + '495a23fce9cd125f715dc20643d14fed226d76ac', - - # Build tools for Chrome OS. - 'src/third_party/chromite': - Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'dda64836fc8b02ed89fed167603a838007e99712', - - # Dependency of chromite.git. - 'src/third_party/pyelftools': - Var('chromium_git') + '/chromiumos/third_party/pyelftools.git' + '@' + 'bdc1d380acd88d4bfaf47265008091483b0d614e', - - 'src/third_party/undoview': - Var('chromium_git') + '/chromium/deps/undoview.git' + '@' + '3ba503e248f3cdbd81b78325a24ece0984637559', - - 'src/third_party/liblouis/src': - Var('chromium_git') + '/external/liblouis-github.git' + '@' + '5f9c03f2a3478561deb6ae4798175094be8a26c2', - - # Used for embedded builds. CrOS & Linux use the system version. - 'src/third_party/fontconfig/src': - Var('chromium_git') + '/external/fontconfig.git' + '@' + 'f16c3118e25546c1b749f9823c51827a60aeb5c1', - }, - 'android': { - 'src/third_party/android_protobuf/src': - Var('chromium_git') + '/external/android_protobuf.git' + '@' + '94f522f907e3f34f70d9e7816b947e62fddbb267', - - # Whenever you roll this please also change frameworks/webview in - # src/android_webview/buildbot/aosp_manifest.xml to point to the same revision. - 'src/third_party/android_webview_glue/src': - Var('chromium_git') + '/external/android_webview_glue.git' + '@' + '7d62eab4ca242beacac4471c002e998ef5c218b8', - - 'src/third_party/android_tools': - Var('chromium_git') + '/android_tools.git' + '@' + 'ea50cccc11657404ce22cf928062ed1a3927eb39', - - 'src/third_party/apache-mime4j': - Var('chromium_git') + '/chromium/deps/apache-mime4j.git' + '@' + '28cb1108bff4b6cf0a2e86ff58b3d025934ebe3a', - - 'src/third_party/findbugs': - Var('chromium_git') + '/chromium/deps/findbugs.git' + '@' + '7f69fa78a6db6dc31866d09572a0e356e921bf12', - - 'src/third_party/freetype': - Var('chromium_git') + '/chromium/src/third_party/freetype.git' + '@' + 'a2b9955b49034a51dfbc8bf9f4e9d312149cecac', - - 'src/third_party/elfutils/src': - Var('chromium_git') + '/external/elfutils.git' + '@' + '249673729a7e5dbd5de4f3760bdcaa3d23d154d7', - - 'src/third_party/httpcomponents-client': - Var('chromium_git') + '/chromium/deps/httpcomponents-client.git' + '@' + '285c4dafc5de0e853fa845dce5773e223219601c', - - 'src/third_party/httpcomponents-core': - Var('chromium_git') + '/chromium/deps/httpcomponents-core.git' + '@' + '9f7180a96f8fa5cab23f793c14b413356d419e62', - - 'src/third_party/jarjar': - Var('chromium_git') + '/chromium/deps/jarjar.git' + '@' + '2e1ead4c68c450e0b77fe49e3f9137842b8b6920', - - 'src/third_party/jsr-305/src': - Var('chromium_git') + '/external/jsr-305.git' + '@' + '642c508235471f7220af6d5df2d3210e3bfc0919', - - 'src/third_party/junit/src': - Var('chromium_git') + '/external/junit.git' + '@' + 'c62e2df8dbecccb1b434d4ba8843b59e90b03266', - - 'src/third_party/lss': - Var('chromium_git') + '/external/linux-syscall-support/lss.git' + '@' + Var('lss_revision'), - - 'src/third_party/eyesfree/src/android/java/src/com/googlecode/eyesfree/braille': - Var('chromium_git') + '/external/eyes-free/braille/client/src/com/googlecode/eyesfree/braille.git' + '@' + '77bf6edb0138e3a38a2772248696f130dab45e34', - }, -} - - -include_rules = [ - # Everybody can use some things. - '+base', - '+build', - '+ipc', - - # Everybody can use headers generated by tools/generate_library_loader. - '+library_loaders', - - '+testing', - '+third_party/icu/source/common/unicode', - '+third_party/icu/source/i18n/unicode', - '+url', -] - - -# checkdeps.py shouldn't check include paths for files in these dirs: -skip_child_includes = [ - 'breakpad', - 'delegate_execute', - 'metro_driver', - 'native_client_sdk', - 'o3d', - 'sdch', - 'skia', - 'testing', - 'third_party', - 'v8', - 'win8', -] - - -hooks = [ - { - # This clobbers when necessary (based on get_landmines.py). It must be the - # first hook so that other things that get/generate into the output - # directory will not subsequently be clobbered. - 'name': 'landmines', - 'pattern': '.', - 'action': [ - 'python', - 'src/build/landmines.py', - ], - }, - { - # This downloads binaries for Native Client's newlib toolchain. - # Done in lieu of building the toolchain from scratch as it can take - # anywhere from 30 minutes to 4 hours depending on platform to build. - 'name': 'nacltools', - 'pattern': '.', - 'action': [ - 'python', 'src/build/download_nacl_toolchains.py', - '--exclude', 'arm_trusted', - ], - }, - { - # Downloads the Debian Wheezy sysroot to chrome/installer/linux if needed. - # This sysroot updates at about the same rate that the chrome build deps - # change. This script is a no-op except for linux users who are doing - # official chrome builds. - 'name': 'sysroot', - 'pattern': '.', - 'action': [ - 'python', - 'src/chrome/installer/linux/sysroot_scripts/install-debian.wheezy.sysroot.py', - '--linux-only', - '--arch=amd64'], - }, - { - # Same as above, but for 32-bit Linux. - 'name': 'sysroot', - 'pattern': '.', - 'action': [ - 'python', - 'src/chrome/installer/linux/sysroot_scripts/install-debian.wheezy.sysroot.py', - '--linux-only', - '--arch=i386'], - }, - { - # Same as above, but for ARM Linux. - 'name': 'sysroot', - 'pattern': '.', - 'action': [ - 'python', - 'src/chrome/installer/linux/sysroot_scripts/install-debian.wheezy.sysroot.py', - '--linux-only', - '--arch=arm'], - }, - { - # Update the Windows toolchain if necessary. - 'name': 'win_toolchain', - 'pattern': '.', - 'action': ['python', 'src/build/vs_toolchain.py', 'update'], - }, - { - # Pull clang if needed or requested via GYP_DEFINES. - # Note: On Win, this should run after win_toolchain, as it may use it. - 'name': 'clang', - 'pattern': '.', - 'action': ['python', 'src/tools/clang/scripts/update.py', '--if-needed'], - }, - { - # Update LASTCHANGE. This is also run by export_tarball.py in - # src/tools/export_tarball - please keep them in sync. - 'name': 'lastchange', - 'pattern': '.', - 'action': ['python', 'src/build/util/lastchange.py', - '-o', 'src/build/util/LASTCHANGE'], - }, - { - # Update LASTCHANGE.blink. This is also run by export_tarball.py in - # src/tools/export_tarball - please keep them in sync. - 'name': 'lastchange', - 'pattern': '.', - 'action': ['python', 'src/build/util/lastchange.py', - '-s', 'src/third_party/WebKit', - '-o', 'src/build/util/LASTCHANGE.blink'], - }, - # Pull GN binaries. This needs to be before running GYP below. - { - 'name': 'gn_win', - 'pattern': '.', - 'action': [ 'download_from_google_storage', - '--no_resume', - '--platform=win32', - '--no_auth', - '--bucket', 'chromium-gn', - '-s', 'src/buildtools/win/gn.exe.sha1', - ], - }, - { - 'name': 'gn_mac', - 'pattern': '.', - 'action': [ 'download_from_google_storage', - '--no_resume', - '--platform=darwin', - '--no_auth', - '--bucket', 'chromium-gn', - '-s', 'src/buildtools/mac/gn.sha1', - ], - }, - { - 'name': 'gn_linux32', - 'pattern': '.', - 'action': [ 'download_from_google_storage', - '--no_resume', - '--platform=linux*', - '--no_auth', - '--bucket', 'chromium-gn', - '-s', 'src/buildtools/linux32/gn.sha1', - ], - }, - { - 'name': 'gn_linux64', - 'pattern': '.', - 'action': [ 'download_from_google_storage', - '--no_resume', - '--platform=linux*', - '--no_auth', - '--bucket', 'chromium-gn', - '-s', 'src/buildtools/linux64/gn.sha1', - ], - }, - # Pull clang-format binaries using checked-in hashes. - { - 'name': 'clang_format_win', - 'pattern': '.', - 'action': [ 'download_from_google_storage', - '--no_resume', - '--platform=win32', - '--no_auth', - '--bucket', 'chromium-clang-format', - '-s', 'src/buildtools/win/clang-format.exe.sha1', - ], - }, - { - 'name': 'clang_format_mac', - 'pattern': '.', - 'action': [ 'download_from_google_storage', - '--no_resume', - '--platform=darwin', - '--no_auth', - '--bucket', 'chromium-clang-format', - '-s', 'src/buildtools/mac/clang-format.sha1', - ], - }, - { - 'name': 'clang_format_linux', - 'pattern': '.', - 'action': [ 'download_from_google_storage', - '--no_resume', - '--platform=linux*', - '--no_auth', - '--bucket', 'chromium-clang-format', - '-s', 'src/buildtools/linux64/clang-format.sha1', - ], - }, - # Pull binutils for linux, enabled debug fission for faster linking / - # debugging when used with clang on Ubuntu Precise. - # https://code.google.com/p/chromium/issues/detail?id=352046 - { - 'name': 'binutils', - 'pattern': 'src/third_party/binutils', - 'action': [ - 'python', - 'src/third_party/binutils/download.py', - ], - }, - # Pull eu-strip binaries using checked-in hashes. - { - 'name': 'eu-strip', - 'pattern': '.', - 'action': [ 'download_from_google_storage', - '--no_resume', - '--platform=linux*', - '--no_auth', - '--bucket', 'chromium-eu-strip', - '-s', 'src/build/linux/bin/eu-strip.sha1', - ], - }, - { - 'name': 'drmemory', - 'pattern': '.', - 'action': [ 'download_from_google_storage', - '--no_resume', - '--platform=win32', - '--no_auth', - '--bucket', 'chromium-drmemory', - '-s', 'src/third_party/drmemory/drmemory-windows-sfx.exe.sha1', - ], - }, - # Pull the Syzygy binaries, used for optimization and instrumentation. - { - 'name': 'syzygy-binaries', - 'pattern': '.', - 'action': ['python', - 'src/build/get_syzygy_binaries.py', - '--output-dir=src/third_party/syzygy/binaries', - '--revision=52a58e8bb19c5dcc97970bae4b8c00c5891f3568', - '--overwrite', - ], - }, - { - 'name': 'apache_win32', - 'pattern': '\\.sha1', - 'action': [ 'download_from_google_storage', - '--no_resume', - '--platform=win32', - '--directory', - '--recursive', - '--no_auth', - '--num_threads=16', - '--bucket', 'chromium-apache-win32', - 'src/third_party/apache-win32', - ], - }, - { - # A change to a .gyp, .gypi, or to GYP itself should run the generator. - 'name': 'gyp', - 'pattern': '.', - 'action': ['python', 'src/build/gyp_chromium'], - }, - { - # Verify committers' ~/.netc, gclient and git are properly configured for - # write access to the git repo. To be removed sometime after Chrome to git - # migration completes (let's say Sep 1 2014). - 'name': 'check_git_config', - 'pattern': '.', - 'action': [ - 'python', - 'src/tools/check_git_config.py', - '--running-as-hook', - ], - }, - { - # Ensure that we don't accidentally reference any .pyc files whose - # corresponding .py files have already been deleted. - 'name': 'remove_stale_pyc_files', - 'pattern': 'src/tools/.*\\.py', - 'action': [ - 'python', - 'src/tools/remove_stale_pyc_files.py', - 'src/tools', - ], - }, -] +vars = { + 'eyes-free': + 'http://eyes-free.googlecode.com/svn', + 'blink': + 'http://src.chromium.org/blink', + 'skia': + 'http://skia.googlecode.com/svn', + 'google-breakpad': + 'http://google-breakpad.googlecode.com/svn', + 'sawbuck': + 'http://sawbuck.googlecode.com/svn', + 'mozc': + 'http://mozc.googlecode.com/svn', + 'git.chromium.org': + 'https://chromium.googlesource.com', + 'v8-i18n': + 'http://v8-i18n.googlecode.com/svn', + 'selenium': + 'http://selenium.googlecode.com/svn', + 'buildspec_platforms': + 'all', + 'snappy': + 'http://snappy.googlecode.com/svn', + 'ppapi': + 'http://ppapi.googlecode.com/svn', + 'pywebsocket': + 'http://pywebsocket.googlecode.com/svn', + 'libaddressinput': + 'http://libaddressinput.googlecode.com/svn', + 'pyftpdlib': + 'http://pyftpdlib.googlecode.com/svn', + 'google-url': + 'http://google-url.googlecode.com/svn', + 'googletest': + 'http://googletest.googlecode.com/svn', + 'gyp': + 'http://gyp.googlecode.com/svn', + 'seccompsandbox': + 'http://seccompsandbox.googlecode.com/svn', + 'ots': + 'http://ots.googlecode.com/svn', + 'angleproject': + 'http://angleproject.googlecode.com/svn', + 'pefile': + 'http://pefile.googlecode.com/svn', + 'open-vcdiff': + 'http://open-vcdiff.googlecode.com/svn', + 'linux-syscall-support': + 'http://linux-syscall-support.googlecode.com/svn', + 'trace-viewer': + 'http://trace-viewer.googlecode.com/svn', + 'webrtc': + 'http://webrtc.googlecode.com/svn', + 'web-page-replay': + 'http://web-page-replay.googlecode.com/svn', + 'libjingle': + 'http://libjingle.googlecode.com/svn', + 'cld2': + 'https://cld2.googlecode.com/svn', + 'google-cache-invalidation-api': + 'http://google-cache-invalidation-api.googlecode.com/svn', + 'jsr-305': + 'http://jsr-305.googlecode.com/svn', + 'bidichecker': + 'http://bidichecker.googlecode.com/svn', + 'native_client': + 'http://src.chromium.org/native_client', + 'jsoncpp': + 'http://svn.code.sf.net/p/jsoncpp/code', + 'leveldb': + 'http://leveldb.googlecode.com/svn', + 'webkit_trunk': + 'http://src.chromium.org/blink/trunk', + 'google-toolbox-for-mac': + 'http://google-toolbox-for-mac.googlecode.com/svn', + 'grit-i18n': + 'http://grit-i18n.googlecode.com/svn', + 'pdfsqueeze': + 'http://pdfsqueeze.googlecode.com/svn', + 'protobuf': + 'http://protobuf.googlecode.com/svn', + 'smhasher': + 'http://smhasher.googlecode.com/svn', + 'googlemock': + 'http://googlemock.googlecode.com/svn', + 'libyuv': + 'http://libyuv.googlecode.com/svn', + 'rlz': + 'http://rlz.googlecode.com/svn', + 'v8': + 'http://v8.googlecode.com/svn', + 'pymox': + 'http://pymox.googlecode.com/svn', + 'sfntly': + 'http://sfntly.googlecode.com/svn', + 'sctp-refimpl': + 'https://sctp-refimpl.googlecode.com/svn', + 'libphonenumber': + 'http://libphonenumber.googlecode.com/svn', + 'octane-benchmark': + 'http://octane-benchmark.googlecode.com/svn', + 'google-safe-browsing': + 'http://google-safe-browsing.googlecode.com/svn' +} + +deps_os = { + 'win': { + 'src/third_party/yasm/binaries': + (Var("git.chromium.org")) + '/chromium/deps/yasm/binaries.git@52f9b3f4b0aa06da24ef8b123058bb61ee468881', + 'src/chrome/tools/test/reference_build/chrome_win': + (Var("git.chromium.org")) + '/chromium/reference_builds/chrome_win.git@f8a3a845dfc845df6b14280f04f86a61959357ef', + 'src/third_party/nacl_sdk_binaries': + (Var("git.chromium.org")) + '/chromium/deps/nacl_sdk_binaries.git@759dfca03bdc774da7ecbf974f6e2b84f43699a5', + 'src/third_party/lighttpd': + (Var("git.chromium.org")) + '/chromium/deps/lighttpd.git@9dfa55d15937a688a92cbf2b7a8621b0927d06eb', + 'src/third_party/gnu_binutils': + (Var("git.chromium.org")) + '/native_client/deps/third_party/gnu_binutils.git@f4003433b61b25666565690caf3d7a7a1a4ec436', + 'src/third_party/pefile': + (Var("git.chromium.org")) + '/external/pefile.git@72c6ae42396cb913bcab63c15585dc3b5c3f92f1', + 'src/third_party/psyco_win32': + (Var("git.chromium.org")) + '/chromium/deps/psyco_win32.git@f5af9f6910ee5a8075bbaeed0591469f1661d868', + 'src/third_party/mingw-w64/mingw/bin': + (Var("git.chromium.org")) + '/native_client/deps/third_party/mingw-w64/mingw/bin.git@3cc8b140b883a9fe4986d12cfd46c16a093d3527', + 'src/third_party/perl': + (Var("git.chromium.org")) + '/chromium/deps/perl.git@ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78', + 'src/third_party/omaha/src/omaha': + (Var("git.chromium.org")) + '/external/omaha.git@098c7a3d157218dab4eed595e8f2fbe5a20a0bae', + 'src/third_party/gperf': + (Var("git.chromium.org")) + '/chromium/deps/gperf.git@d892d79f64f9449770443fb06da49b5a1e5d33c1', + 'src/third_party/cygwin': + (Var("git.chromium.org")) + '/chromium/deps/cygwin.git@c89e446b273697fadf3a10ff1007a97c0b7de6df', + 'src/third_party/swig/win': + (Var("git.chromium.org")) + '/chromium/deps/swig/win.git@986f013ba518541adf5c839811efb35630a31031', + 'src/third_party/bison': + (Var("git.chromium.org")) + '/chromium/deps/bison.git@083c9a45e4affdd5464ee2b224c2df649c6e26c3', + 'src/third_party/nss': + (Var("git.chromium.org")) + '/chromium/deps/nss.git@a4192054ee0a9902ec81e53bc7a5c2ea2991d764' + }, + 'mac': { + 'src/third_party/pdfsqueeze': + (Var("git.chromium.org")) + '/external/pdfsqueeze.git@5936b871e6a087b7e50d4cbcb122378d8a07499f', + 'src/chrome/installer/mac/third_party/xz/xz': + (Var("git.chromium.org")) + '/chromium/deps/xz.git@eecaf55632ca72e90eb2641376bce7cdbc7284f7', + 'src/third_party/lighttpd': + (Var("git.chromium.org")) + '/chromium/deps/lighttpd.git@9dfa55d15937a688a92cbf2b7a8621b0927d06eb', + 'src/third_party/swig/mac': + (Var("git.chromium.org")) + '/chromium/deps/swig/mac.git@1b182eef16df2b506f1d710b34df65d55c1ac44e', + 'src/third_party/google_toolbox_for_mac/src': + (Var("git.chromium.org")) + '/external/google-toolbox-for-mac.git@a09526298f9dd1ec49d3b3ac5608d2a257b94cef', + 'src/chrome/tools/test/reference_build/chrome_mac': + (Var("git.chromium.org")) + '/chromium/reference_builds/chrome_mac.git@8dc181329e7c5255f83b4b85dc2f71498a237955', + 'src/third_party/nss': + (Var("git.chromium.org")) + '/chromium/deps/nss.git@a4192054ee0a9902ec81e53bc7a5c2ea2991d764' + }, + 'ios': { + 'src/chrome/test/data/perf/canvas_bench': None, + 'src/chrome/test/data/perf/frame_rate/content': None, + 'src/third_party/google_toolbox_for_mac/src': + (Var("git.chromium.org")) + '/external/google-toolbox-for-mac.git@a09526298f9dd1ec49d3b3ac5608d2a257b94cef', + 'src/third_party/hunspell_dictionaries': None, + 'src/native_client': None, + 'src/third_party/webgl': None, + 'src/third_party/hunspell': None, + 'src/testing/iossim/third_party/class-dump': + (Var("git.chromium.org")) + '/chromium/deps/class-dump.git@89bd40883c767584240b4dade8b74e6f57b9bdab', + 'src/third_party/cld_2/src': None, + 'src/third_party/ffmpeg': None, + 'src/third_party/nss': + (Var("git.chromium.org")) + '/chromium/deps/nss.git@a4192054ee0a9902ec81e53bc7a5c2ea2991d764' + }, + 'unix': { + 'src/third_party/fontconfig/src': + (Var("git.chromium.org")) + '/external/fontconfig.git@f16c3118e25546c1b749f9823c51827a60aeb5c1', + 'build/third_party/cbuildbot_chromite': + (Var("git.chromium.org")) + '/chromiumos/chromite.git@38de38fd79fab228e693a1b22e60e2fa69bf85fd', + 'src/third_party/cros_system_api': + (Var("git.chromium.org")) + '/chromiumos/platform/system_api.git@a21c902a409c2238c0a73a44e8fe11f1ed9535a5', + 'src/third_party/pyelftools': + (Var("git.chromium.org")) + '/chromiumos/third_party/pyelftools.git@bdc1d380acd88d4bfaf47265008091483b0d614e', + 'src/third_party/chromite': + (Var("git.chromium.org")) + '/chromiumos/chromite.git@dda64836fc8b02ed89fed167603a838007e99712', + 'build/third_party/xvfb': + '/trunk/tools/third_party/xvfb@125214', + 'src/third_party/xdg-utils': + (Var("git.chromium.org")) + '/chromium/deps/xdg-utils.git@d80274d5869b17b8c9067a1022e4416ee7ed5e0d', + 'src/third_party/undoview': + (Var("git.chromium.org")) + '/chromium/deps/undoview.git@3ba503e248f3cdbd81b78325a24ece0984637559', + 'src/chrome/tools/test/reference_build/chrome_linux': + (Var("git.chromium.org")) + '/chromium/reference_builds/chrome_linux64.git@033d053a528e820e1de3e2db766678d862a86b36', + 'src/third_party/swig/linux': + (Var("git.chromium.org")) + '/chromium/deps/swig/linux.git@866b8e0e0e0cfe99ebe608260030916ca0c3f92d', + 'src/third_party/liblouis/src': + (Var("git.chromium.org")) + '/external/liblouis-github.git@5f9c03f2a3478561deb6ae4798175094be8a26c2', + 'src/third_party/freetype2/src': + (Var("git.chromium.org")) + '/chromium/src/third_party/freetype2.git@495a23fce9cd125f715dc20643d14fed226d76ac', + 'src/third_party/lss': + (Var("git.chromium.org")) + '/external/linux-syscall-support/lss.git@952107fa7cea0daaabead28c0e92d579bee517eb' + }, + 'android': { + 'src/third_party/android_webview_glue/src': + (Var("git.chromium.org")) + '/external/android_webview_glue.git@7d62eab4ca242beacac4471c002e998ef5c218b8', + 'src/third_party/jarjar': + (Var("git.chromium.org")) + '/chromium/deps/jarjar.git@2e1ead4c68c450e0b77fe49e3f9137842b8b6920', + 'src/third_party/eyesfree/src/android/java/src/com/googlecode/eyesfree/braille': + (Var("git.chromium.org")) + '/external/eyes-free/braille/client/src/com/googlecode/eyesfree/braille.git@77bf6edb0138e3a38a2772248696f130dab45e34', + 'src/third_party/freetype': + (Var("git.chromium.org")) + '/chromium/src/third_party/freetype.git@a2b9955b49034a51dfbc8bf9f4e9d312149cecac', + 'src/third_party/apache-mime4j': + (Var("git.chromium.org")) + '/chromium/deps/apache-mime4j.git@28cb1108bff4b6cf0a2e86ff58b3d025934ebe3a', + 'src/third_party/elfutils/src': + (Var("git.chromium.org")) + '/external/elfutils.git@249673729a7e5dbd5de4f3760bdcaa3d23d154d7', + 'src/pdf': None, + 'src/third_party/junit/src': + (Var("git.chromium.org")) + '/external/junit.git@c62e2df8dbecccb1b434d4ba8843b59e90b03266', + 'src/third_party/android_tools': + (Var("git.chromium.org")) + '/android_tools.git@4c47ef63519d579b9ac029fcb6dcc81e38d82984', + 'src/third_party/httpcomponents-client': + (Var("git.chromium.org")) + '/chromium/deps/httpcomponents-client.git@285c4dafc5de0e853fa845dce5773e223219601c', + 'src/third_party/findbugs': + (Var("git.chromium.org")) + '/chromium/deps/findbugs.git@7f69fa78a6db6dc31866d09572a0e356e921bf12', + 'src/third_party/lss': + (Var("git.chromium.org")) + '/external/linux-syscall-support/lss.git@952107fa7cea0daaabead28c0e92d579bee517eb', + 'src/third_party/android_protobuf/src': + (Var("git.chromium.org")) + '/external/android_protobuf.git@94f522f907e3f34f70d9e7816b947e62fddbb267', + 'src/third_party/jsr-305/src': + (Var("git.chromium.org")) + '/external/jsr-305.git@642c508235471f7220af6d5df2d3210e3bfc0919', + 'src/third_party/httpcomponents-core': + (Var("git.chromium.org")) + '/chromium/deps/httpcomponents-core.git@9f7180a96f8fa5cab23f793c14b413356d419e62' + } +} + +deps = { + 'depot_tools': + '/trunk/tools/depot_tools@292868', + 'src/third_party/sfntly/cpp/src': + (Var("git.chromium.org")) + '/external/sfntly/cpp/src.git@1bdaae8fc788a5ac8936d68bf24f37d977a13dac', + 'src/third_party/bidichecker': + (Var("git.chromium.org")) + '/external/bidichecker/lib.git@97f2aa645b74c28c57eca56992235c79850fa9e0', + 'src/third_party/libc++/trunk': + (Var("git.chromium.org")) + '/chromium/llvm-project/libcxx.git@48198f9110397fff47fe7c37cbfa296be7d44d3d', + 'src/third_party/colorama/src': + (Var("git.chromium.org")) + '/external/colorama.git@799604a1041e9b3bc5d2789ecbd7e8db2e18e6b8', + 'src/third_party/libwebm/source': + (Var("git.chromium.org")) + '/webm/libwebm.git@0d4cb404ea4195e5e21d04db2c955615535ce62e', + 'src/third_party/usrsctp/usrsctplib': + (Var("git.chromium.org")) + '/external/usrsctplib.git@190c8cbfcf8fd810aa09e0fab4ca62a8ce724e14', + 'src/third_party/openmax_dl': + (Var("git.chromium.org")) + '/external/webrtc/deps/third_party/openmax.git@01642706d2b37cb7b9db84add870ea0fdabdf5ad', + 'src/third_party/libc++abi/trunk': + (Var("git.chromium.org")) + '/chromium/llvm-project/libcxxabi.git@4ad1009ab3a59fa7a6896d74d5e4de5885697f95', + 'build/scripts/private/data/reliability': + '/trunk/src/chrome/test/data/reliability@291312', + 'src/third_party/flac': + (Var("git.chromium.org")) + '/chromium/deps/flac.git@0635a091379d9677f1ddde5f2eec85d0f096f219', + 'src/media/cdm/ppapi/api': + (Var("git.chromium.org")) + '/chromium/cdm.git@f924b6382b05c57677455ac40f210b33809591ef', + 'src/third_party/skia': + (Var("git.chromium.org")) + '/skia.git@2e74f758f8379338f75898f28128ade1dfcf3702', + 'src/tools/swarming_client': + (Var("git.chromium.org")) + '/external/swarming.client.git@1f8ba359e84dc7f26b1ba286dfb4e28674efbff4', + 'src/chrome/test/data/perf/frame_rate/content': + (Var("git.chromium.org")) + '/chromium/frame_rate/content.git@c10272c88463efeef6bb19c9ec07c42bc8fe22b9', + 'src/third_party/ots': + (Var("git.chromium.org")) + '/external/ots.git@98897009f3ea8a5fa3e20a4a74977da7aaa8e61a', + 'src/third_party/jsoncpp/source/src/lib_json': + (Var("git.chromium.org")) + '/external/jsoncpp/jsoncpp/src/lib_json.git@a8caa51ba2f80971a45880425bf2ae864a786784', + 'src/third_party/cld_2/src': + (Var("git.chromium.org")) + '/external/cld2.git@14d9ef8d4766326f8aa7de54402d1b9c782d4481', + 'src/third_party/webgl/src': + (Var("git.chromium.org")) + '/external/khronosgroup/webgl.git@152f156d821aeeb688d0979daa529cdad44c0bc7', + 'src/testing/gmock': + (Var("git.chromium.org")) + '/external/googlemock.git@896ba0e03f520fb9b6ed582bde2bd00847e3c3f2', + 'src/third_party/libsrtp': + (Var("git.chromium.org")) + '/chromium/deps/libsrtp.git@6446144c7f083552f21cc4e6768e891bcb767574', + 'src/third_party/mesa/src': + (Var("git.chromium.org")) + '/chromium/deps/mesa.git@9731cb962963bca8a05f3d0f6ea40c3a781f0537', + 'src/third_party/smhasher/src': + (Var("git.chromium.org")) + '/external/smhasher.git@e87738e57558e0ec472b2fc3a643b838e5b6e88f', + 'src/third_party/webrtc': + (Var("git.chromium.org")) + '/external/webrtc/trunk/webrtc.git@71616dbb8cdd3ea13e0a964d18456ca3fe002dab', + 'build/scripts/tools/deps2git': + '/trunk/tools/deps2git@292856', + 'src/third_party/hunspell_dictionaries': + (Var("git.chromium.org")) + '/chromium/deps/hunspell_dictionaries.git@4560bdd463a3500e2334e85c8a0e9e5d5d6774e7', + 'src/native_client': + (Var("git.chromium.org")) + '/native_client/src/native_client.git@9cd80947288ebca86dd07b55171089b84553a7c7', + 'src/third_party/brotli/src': + (Var("git.chromium.org")) + '/external/font-compression-reference.git@65cb3326e30ef8a67eb1d4411ec563e91be6e9ae', + 'src/third_party/cacheinvalidation/src': + (Var("git.chromium.org")) + '/external/google-cache-invalidation-api/src.git@c91bd9d9fed06bf440be64f87b94a2effdb32bc4', + 'src/third_party/leveldatabase/src': + (Var("git.chromium.org")) + '/external/leveldb.git@3f77584eb3f9754bbb7079070873ece3f30a1e6b', + 'build': + '/trunk/tools/build@292886', + 'src/tools/gyp': + (Var("git.chromium.org")) + '/external/gyp.git@487c0b6ae8b44932e45347211bca0e8387718436', + 'src/chrome/test/data/perf/canvas_bench': + (Var("git.chromium.org")) + '/chromium/canvas_bench.git@a7b40ea5ae0239517d78845a5fc9b12976bfc732', + 'src/sdch/open-vcdiff': + (Var("git.chromium.org")) + '/external/open-vcdiff.git@438f2a5be6d809bc21611a94cd37bfc8c28ceb33', + 'src/third_party/angle': + (Var("git.chromium.org")) + '/angle/angle.git@019fa9340e580e5836a9b9dc7cede4766cd090df', + 'build/third_party/lighttpd': + '/trunk/deps/third_party/lighttpd@58968', + 'src/buildtools': + (Var("git.chromium.org")) + '/chromium/buildtools.git@c27f95bd1d9baaef70c879dea375090dd1496147', + 'src/third_party/scons-2.0.1': + (Var("git.chromium.org")) + '/native_client/src/third_party/scons-2.0.1.git@1c1550e17fc26355d08627fbdec13d8291227067', + 'src/third_party/webdriver/pylib': + (Var("git.chromium.org")) + '/external/selenium/py.git@5fd78261a75fe08d27ca4835fb6c5ce4b42275bd', + 'src/third_party/libaddressinput/src': + (Var("git.chromium.org")) + '/external/libaddressinput.git@51f43544159ce5e2d4e19dfa1673149ba73a0200', + 'build/scripts/gsd_generate_index': + '/trunk/tools/gsd_generate_index@164784', + 'src/chrome/browser/resources/pdf/html_office': + (Var("git.chromium.org")) + '/chromium/html-office-public.git@eeff97614f65e0578529490d44d412032c3d7359', + 'src/tools/page_cycler/acid3': + (Var("git.chromium.org")) + '/chromium/deps/acid3.git@6be0a66a1ebd7ebc5abc1b2f405a945f6d871521', + 'src/third_party/libyuv': + (Var("git.chromium.org")) + '/external/libyuv.git@5a09c3ef2aa3e6b6da4007746fdde04ca56dae7c', + 'src/third_party/libjingle/source/talk': + (Var("git.chromium.org")) + '/external/webrtc/trunk/talk.git@f97800413f157c911aefbf5be167dbd4806a2323', + 'src/third_party/libexif/sources': + (Var("git.chromium.org")) + '/chromium/deps/libexif/sources.git@ed98343daabd7b4497f97fda972e132e6877c48a', + 'src/third_party/jsoncpp/source/include': + (Var("git.chromium.org")) + '/external/jsoncpp/jsoncpp/include.git@b0dd48e02b6e6248328db78a65b5c601f150c349', + 'src/third_party/libphonenumber/src/test': + (Var("git.chromium.org")) + '/external/libphonenumber/cpp/test.git@883b7b86541d64b2691f7c0e65facb0b08db73e8', + 'src/third_party/pdfium': + 'https://pdfium.googlesource.com/pdfium.git@4dc95e74e1acc75f4eab08bc771874cd2a9c3a9b', + 'src/third_party/libphonenumber/src/phonenumbers': + (Var("git.chromium.org")) + '/external/libphonenumber/cpp/src/phonenumbers.git@8d8b5b3b2035197795d27573d4cf566b5d9ad689', + 'src/third_party/libphonenumber/src/resources': + (Var("git.chromium.org")) + '/external/libphonenumber/resources.git@de095548d2ae828a414e01f3951bfefba902b4e4', + 'src/third_party/trace-viewer': + (Var("git.chromium.org")) + '/external/trace-viewer.git@c3820e9a59e1d2869a7848c4a65cb7aed08b915d', + 'src/third_party/yasm/source/patched-yasm': + (Var("git.chromium.org")) + '/chromium/deps/yasm/patched-yasm.git@c960eb11ccda80b10ed50be39df4f0663b371d1d', + 'src/third_party/safe_browsing/testing': + (Var("git.chromium.org")) + '/external/google-safe-browsing/testing.git@9d7e8064f3ca2e45891470c9b5b1dce54af6a9d6', + 'src/third_party/ffmpeg': + (Var("git.chromium.org")) + '/chromium/third_party/ffmpeg.git@399d38b9baba60763e1db26be5d6a8577a4276f4', + 'build/scripts/command_wrapper/bin': + '/trunk/tools/command_wrapper/bin@135178', + 'src/third_party/pyftpdlib/src': + (Var("git.chromium.org")) + '/external/pyftpdlib.git@2be6d65e31c7ee6320d059f581f05ae8d89d7e45', + 'src/third_party/icu': + (Var("git.chromium.org")) + '/chromium/deps/icu52.git@dd727641e190d60e4593bcb3a35c7f51eb4925c5', + 'src/third_party/opus/src': + (Var("git.chromium.org")) + '/chromium/deps/opus.git@cae696156f1e60006e39821e79a1811ae1933c69', + 'src/tools/grit': + (Var("git.chromium.org")) + '/external/grit-i18n.git@a24a0e647bb718b3540db89864cf586b12331e82', + 'src/third_party/snappy/src': + (Var("git.chromium.org")) + '/external/snappy.git@762bb32f0c9d2f31ba4958c7c0933d22e80c20bf', + 'src/third_party/webpagereplay': + (Var("git.chromium.org")) + '/external/web-page-replay.git@2f7b704b8b567983c040f555d3e46f9766db8e87', + 'src/third_party/WebKit': + (Var("git.chromium.org")) + '/chromium/blink.git@045e2df1e88cddebce6d9690812b5233c896e201', + 'src/breakpad/src': + (Var("git.chromium.org")) + '/external/google-breakpad/src.git@f37b59821ecbd69c54f3388026d2e98cd8b2fba2', + 'src/third_party/py_trace_event/src': + (Var("git.chromium.org")) + '/external/py_trace_event.git@dd463ea9e2c430de2b9e53dea57a77b4c3ac9b30', + 'src/third_party/hunspell': + (Var("git.chromium.org")) + '/chromium/deps/hunspell.git@c956c0e97af00ef789afb2f64d02c9a5a50e6eb1', + 'src/tools/deps2git': + (Var("git.chromium.org")) + '/chromium/tools/deps2git.git@f04828eb0b5acd3e7ad983c024870f17f17b06d9', + 'src/third_party/libjpeg_turbo': + (Var("git.chromium.org")) + '/chromium/deps/libjpeg_turbo.git@034e9a9747e0983bc19808ea70e469bc8342081f', + 'src/testing/gtest': + (Var("git.chromium.org")) + '/external/googletest.git@4650552ff637bb44ecf7784060091cbed3252211', + 'src/v8': + (Var("git.chromium.org")) + '/v8/v8.git@d2f16971bdcc2899e0939815005f43253e3e7410', + 'src/third_party/pywebsocket/src': + (Var("git.chromium.org")) + '/external/pywebsocket/src.git@cb349e87ddb30ff8d1fa1a89be39cec901f4a29c', + 'src/third_party/libvpx': + (Var("git.chromium.org")) + '/chromium/deps/libvpx.git@2e5ced5fd62a73f4f5687ab19520b3aad1c53f6f', + 'src/third_party/boringssl/src': + 'https://boringssl.googlesource.com/boringssl.git@817ec3462e246b8301a73e44854e2bb3df90d5e6', + 'src/third_party/swig/Lib': + (Var("git.chromium.org")) + '/chromium/deps/swig/Lib.git@f2a695d52e61e6a8d967731434f165ed400f0d69' +} + +skip_child_includes = [ + 'breakpad', + 'delegate_execute', + 'metro_driver', + 'native_client_sdk', + 'o3d', + 'sdch', + 'skia', + 'testing', + 'third_party', + 'v8', + 'win8' +] + +hooks = [{ + 'action': ['python', + 'src/build/landmines.py'], + 'pattern': + '.', + 'name': + 'landmines' +}, +{ + 'action': ['python', + 'src/build/download_nacl_toolchains.py', + '--exclude', + 'arm_trusted'], + 'pattern': + '.', + 'name': + 'nacltools' +}, +{ + 'action': ['python', + 'src/chrome/installer/linux/sysroot_scripts/install-debian.wheezy.sysroot.py', + '--linux-only', + '--arch=amd64'], + 'pattern': + '.', + 'name': + 'sysroot' +}, +{ + 'action': ['python', + 'src/chrome/installer/linux/sysroot_scripts/install-debian.wheezy.sysroot.py', + '--linux-only', + '--arch=i386'], + 'pattern': + '.', + 'name': + 'sysroot' +}, +{ + 'action': ['python', + 'src/chrome/installer/linux/sysroot_scripts/install-debian.wheezy.sysroot.py', + '--linux-only', + '--arch=arm'], + 'pattern': + '.', + 'name': + 'sysroot' +}, +{ + 'action': ['python', + 'src/build/vs_toolchain.py', + 'update'], + 'pattern': + '.', + 'name': + 'win_toolchain' +}, +{ + 'action': ['python', + 'src/tools/clang/scripts/update.py', + '--if-needed'], + 'pattern': + '.', + 'name': + 'clang' +}, +{ + 'action': ['python', + 'src/build/util/lastchange.py', + '-o', + 'src/build/util/LASTCHANGE'], + 'pattern': + '.', + 'name': + 'lastchange' +}, +{ + 'action': ['python', + 'src/build/util/lastchange.py', + '-s', + 'src/third_party/WebKit', + '-o', + 'src/build/util/LASTCHANGE.blink'], + 'pattern': + '.', + 'name': + 'lastchange' +}, +{ + 'action': ['download_from_google_storage', + '--no_resume', + '--platform=win32', + '--no_auth', + '--bucket', + 'chromium-gn', + '-s', + 'src/buildtools/win/gn.exe.sha1'], + 'pattern': + '.', + 'name': + 'gn_win' +}, +{ + 'action': ['download_from_google_storage', + '--no_resume', + '--platform=darwin', + '--no_auth', + '--bucket', + 'chromium-gn', + '-s', + 'src/buildtools/mac/gn.sha1'], + 'pattern': + '.', + 'name': + 'gn_mac' +}, +{ + 'action': ['download_from_google_storage', + '--no_resume', + '--platform=linux*', + '--no_auth', + '--bucket', + 'chromium-gn', + '-s', + 'src/buildtools/linux32/gn.sha1'], + 'pattern': + '.', + 'name': + 'gn_linux32' +}, +{ + 'action': ['download_from_google_storage', + '--no_resume', + '--platform=linux*', + '--no_auth', + '--bucket', + 'chromium-gn', + '-s', + 'src/buildtools/linux64/gn.sha1'], + 'pattern': + '.', + 'name': + 'gn_linux64' +}, +{ + 'action': ['download_from_google_storage', + '--no_resume', + '--platform=win32', + '--no_auth', + '--bucket', + 'chromium-clang-format', + '-s', + 'src/buildtools/win/clang-format.exe.sha1'], + 'pattern': + '.', + 'name': + 'clang_format_win' +}, +{ + 'action': ['download_from_google_storage', + '--no_resume', + '--platform=darwin', + '--no_auth', + '--bucket', + 'chromium-clang-format', + '-s', + 'src/buildtools/mac/clang-format.sha1'], + 'pattern': + '.', + 'name': + 'clang_format_mac' +}, +{ + 'action': ['download_from_google_storage', + '--no_resume', + '--platform=linux*', + '--no_auth', + '--bucket', + 'chromium-clang-format', + '-s', + 'src/buildtools/linux64/clang-format.sha1'], + 'pattern': + '.', + 'name': + 'clang_format_linux' +}, +{ + 'action': ['python', + 'src/third_party/binutils/download.py'], + 'pattern': + 'src/third_party/binutils', + 'name': + 'binutils' +}, +{ + 'action': ['download_from_google_storage', + '--no_resume', + '--platform=linux*', + '--no_auth', + '--bucket', + 'chromium-eu-strip', + '-s', + 'src/build/linux/bin/eu-strip.sha1'], + 'pattern': + '.', + 'name': + 'eu-strip' +}, +{ + 'action': ['download_from_google_storage', + '--no_resume', + '--platform=win32', + '--no_auth', + '--bucket', + 'chromium-drmemory', + '-s', + 'src/third_party/drmemory/drmemory-windows-sfx.exe.sha1'], + 'pattern': + '.', + 'name': + 'drmemory' +}, +{ + 'action': ['python', + 'src/build/get_syzygy_binaries.py', + '--output-dir=src/third_party/syzygy/binaries', + '--revision=52a58e8bb19c5dcc97970bae4b8c00c5891f3568', + '--overwrite'], + 'pattern': + '.', + 'name': + 'syzygy-binaries' +}, +{ + 'action': ['download_from_google_storage', + '--no_resume', + '--platform=win32', + '--directory', + '--recursive', + '--no_auth', + '--num_threads=16', + '--bucket', + 'chromium-apache-win32', + 'src/third_party/apache-win32'], + 'pattern': + '\\.sha1', + 'name': + 'apache_win32' +}, +{ + 'action': ['python', + 'src/build/gyp_chromium'], + 'pattern': + '.', + 'name': + 'gyp' +}, +{ + 'action': ['python', + 'src/tools/check_git_config.py', + '--running-as-hook'], + 'pattern': + '.', + 'name': + 'check_git_config' +}, +{ + 'action': [ + 'python', + 'src/tools/remove_stale_pyc_files.py', + 'src/tools'], + 'pattern': + 'src/tools/.*\\.py', + 'name': + 'remove_stale_pyc_files' + } +] + +include_rules = [ + '+base', + '+build', + '+ipc', + '+library_loaders', + '+testing', + '+third_party/icu/source/common/unicode', + '+third_party/icu/source/i18n/unicode', + '+url' +] + diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc index c386ad5de5391..ebe8b4be0e094 100644 --- a/android_webview/browser/aw_browser_context.cc +++ b/android_webview/browser/aw_browser_context.cc @@ -11,7 +11,9 @@ #include "android_webview/browser/jni_dependency_factory.h" #include "android_webview/browser/net/aw_url_request_context_getter.h" #include "android_webview/browser/net/init_native_callback.h" +#include "base/base_paths_android.h" #include "base/bind.h" +#include "base/path_service.h" #include "base/prefs/pref_registry_simple.h" #include "base/prefs/pref_service.h" #include "base/prefs/pref_service_factory.h" @@ -28,6 +30,7 @@ #include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" #include "net/cookies/cookie_store.h" +#include "net/proxy/proxy_config_service_android.h" #include "net/proxy/proxy_service.h" using base::FilePath; @@ -43,13 +46,34 @@ namespace { void HandleReadError(PersistentPrefStore::PrefReadError error) { } +void DeleteDirRecursively(const base::FilePath& path) { + if (!base::DeleteFile(path, true)) { + // Deleting a non-existent file is considered successful, so this will + // trigger only in case of real errors. + LOG(WARNING) << "Failed to delete " << path.AsUTF8Unsafe(); + } +} + AwBrowserContext* g_browser_context = NULL; +net::ProxyConfigService* CreateProxyConfigService() { + net::ProxyConfigServiceAndroid* config_service = + static_cast( + net::ProxyService::CreateSystemProxyConfigService( + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO), + nullptr /* Ignored on Android */ )); + config_service->set_exclude_pac_url(true); + return config_service; +} + } // namespace // Data reduction proxy is disabled by default. bool AwBrowserContext::data_reduction_proxy_enabled_ = false; +// Delete the legacy cache dir (in the app data dir) in 10 seconds after init. +int AwBrowserContext::legacy_cache_removal_delay_ms_ = 10000; + AwBrowserContext::AwBrowserContext( const FilePath path, JniDependencyFactory* native_factory) @@ -102,6 +126,11 @@ void AwBrowserContext::SetDataReductionProxyEnabled(bool enabled) { proxy_settings->SetDataReductionProxyEnabled(data_reduction_proxy_enabled_); } +// static +void AwBrowserContext::SetLegacyCacheRemovalDelayForTest(int delay_ms) { + legacy_cache_removal_delay_ms_ = delay_ms; +} + void AwBrowserContext::PreMainMessageLoopRun() { cookie_store_ = CreateCookieStore(this); data_reduction_proxy_settings_.reset( @@ -112,10 +141,7 @@ void AwBrowserContext::PreMainMessageLoopRun() { data_reduction_proxy_config_service( new DataReductionProxyConfigService( scoped_ptr( - net::ProxyService::CreateSystemProxyConfigService( - BrowserThread::GetMessageLoopProxyForThread( - BrowserThread::IO), - NULL /* Ignored on Android */)).Pass())); + CreateProxyConfigService()).Pass())); if (data_reduction_proxy_settings_.get()) { data_reduction_proxy_configurator_.reset( new data_reduction_proxy::DataReductionProxyConfigTracker( @@ -127,8 +153,24 @@ void AwBrowserContext::PreMainMessageLoopRun() { data_reduction_proxy_configurator_.get()); } + FilePath cache_path; + const FilePath fallback_cache_dir = + GetPath().Append(FILE_PATH_LITERAL("Cache")); + if (PathService::Get(base::DIR_CACHE, &cache_path)) { + cache_path = cache_path.Append( + FILE_PATH_LITERAL("org.chromium.android_webview")); + // Delay the legacy dir removal to not impact startup performance. + BrowserThread::PostDelayedTask( + BrowserThread::FILE, FROM_HERE, + base::Bind(&DeleteDirRecursively, fallback_cache_dir), + base::TimeDelta::FromMilliseconds(legacy_cache_removal_delay_ms_)); + } else { + cache_path = fallback_cache_dir; + LOG(WARNING) << "Failed to get cache directory for Android WebView. " + << "Using app data directory as a fallback."; + } url_request_context_getter_ = - new AwURLRequestContextGetter(GetPath(), + new AwURLRequestContextGetter(cache_path, cookie_store_.get(), data_reduction_proxy_config_service.Pass()); diff --git a/android_webview/browser/aw_browser_context.h b/android_webview/browser/aw_browser_context.h index 3f4976538a765..66ac213a83335 100644 --- a/android_webview/browser/aw_browser_context.h +++ b/android_webview/browser/aw_browser_context.h @@ -65,6 +65,7 @@ class AwBrowserContext : public content::BrowserContext, content::WebContents* web_contents); static void SetDataReductionProxyEnabled(bool enabled); + static void SetLegacyCacheRemovalDelayForTest(int delay_ms); // Maps to BrowserMainParts::PreMainMessageLoopRun. void PreMainMessageLoopRun(); @@ -120,6 +121,10 @@ class AwBrowserContext : public content::BrowserContext, void CreateDataReductionProxyStatisticsIfNecessary(); static bool data_reduction_proxy_enabled_; + // Delay, in milliseconds, before removing the legacy cache dir. + // This is non-const for testing purposes. + static int legacy_cache_removal_delay_ms_; + // The file path where data for this context is persisted. base::FilePath context_storage_path_; diff --git a/android_webview/browser/net/aw_url_request_context_getter.cc b/android_webview/browser/net/aw_url_request_context_getter.cc index 33f92a68b4735..b600a460bf291 100644 --- a/android_webview/browser/net/aw_url_request_context_getter.cc +++ b/android_webview/browser/net/aw_url_request_context_getter.cc @@ -175,10 +175,10 @@ scoped_ptr CreateJobFactory( } // namespace AwURLRequestContextGetter::AwURLRequestContextGetter( - const base::FilePath& partition_path, net::CookieStore* cookie_store, + const base::FilePath& cache_path, net::CookieStore* cookie_store, scoped_ptr config_service) - : partition_path_(partition_path), + : cache_path_(cache_path), cookie_store_(cookie_store), net_log_(new net::NetLog()) { data_reduction_proxy_config_service_ = config_service.Pass(); @@ -200,17 +200,18 @@ void AwURLRequestContextGetter::InitializeURLRequestContext() { #if !defined(DISABLE_FTP_SUPPORT) builder.set_ftp_enabled(false); // Android WebView does not support ftp yet. #endif - if (data_reduction_proxy_config_service_.get()) { - builder.set_proxy_config_service( - data_reduction_proxy_config_service_.release()); - } else { - builder.set_proxy_config_service( - net::ProxyService::CreateSystemProxyConfigService( - GetNetworkTaskRunner(), NULL /* Ignored on Android */ )); - } + DCHECK(data_reduction_proxy_config_service_.get()); + // Android provides a local HTTP proxy that handles all the proxying. + // Create the proxy without a resolver since we rely on this local HTTP proxy. + // TODO(sgurun) is this behavior guaranteed through SDK? + builder.set_proxy_service( + net::ProxyService::CreateWithoutProxyResolver( + data_reduction_proxy_config_service_.release(), + net_log_.get())); builder.set_accept_language(net::HttpUtil::GenerateAcceptLanguageHeader( AwContentBrowserClient::GetAcceptLangsImpl())); builder.set_net_log(net_log_.get()); + builder.set_channel_id_enabled(false); ApplyCmdlineOverridesToURLRequestContextBuilder(&builder); url_request_context_.reset(builder.Build()); @@ -225,7 +226,7 @@ void AwURLRequestContextGetter::InitializeURLRequestContext() { new net::HttpCache::DefaultBackend( net::DISK_CACHE, net::CACHE_BACKEND_SIMPLE, - partition_path_.Append(FILE_PATH_LITERAL("Cache")), + cache_path_, 20 * 1024 * 1024, // 20M BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE))); diff --git a/android_webview/browser/net/aw_url_request_context_getter.h b/android_webview/browser/net/aw_url_request_context_getter.h index 25cfaae27d61e..b8afdf8e7af9b 100644 --- a/android_webview/browser/net/aw_url_request_context_getter.h +++ b/android_webview/browser/net/aw_url_request_context_getter.h @@ -35,7 +35,7 @@ class AwNetworkDelegate; class AwURLRequestContextGetter : public net::URLRequestContextGetter { public: AwURLRequestContextGetter( - const base::FilePath& partition_path, + const base::FilePath& cache_path, net::CookieStore* cookie_store, scoped_ptr config_service); @@ -72,7 +72,7 @@ class AwURLRequestContextGetter : public net::URLRequestContextGetter { void InitializeURLRequestContext(); - const base::FilePath partition_path_; + const base::FilePath cache_path_; scoped_refptr cookie_store_; scoped_ptr net_log_; scoped_ptr url_request_context_; diff --git a/android_webview/browser/scoped_app_gl_state_restore.cc b/android_webview/browser/scoped_app_gl_state_restore.cc index 43bd8aa142cdc..2fa1b11ed81b1 100644 --- a/android_webview/browser/scoped_app_gl_state_restore.cc +++ b/android_webview/browser/scoped_app_gl_state_restore.cc @@ -294,6 +294,9 @@ ScopedAppGLStateRestoreImpl::ScopedAppGLStateRestoreImpl( glGetVertexAttribfv( i, GL_CURRENT_VERTEX_ATTRIB, vertex_attrib_[i].current_vertex_attrib); } + + // Android 5.0.0 specific qualcomm workaround. See crbug.com/434570. + glBindRenderbufferEXT(GL_RENDERBUFFER, 0); DCHECK(ClearGLErrors(false, NULL)); } diff --git a/android_webview/common/aw_crash_handler.cc b/android_webview/common/aw_crash_handler.cc index a6372983b1db7..fbd4285b05056 100644 --- a/android_webview/common/aw_crash_handler.cc +++ b/android_webview/common/aw_crash_handler.cc @@ -6,6 +6,9 @@ #include #include +#include +#include +#include #include "base/logging.h" @@ -27,6 +30,14 @@ void AwExceptionHandler(int sig, siginfo_t* info, void* uc) { if (g_crash_msg_ptr != NULL) __android_log_write(ANDROID_LOG_ERROR, "chromium", g_crash_msg_ptr); + // Detect if some buggy code in the embedder did reinstall the handler using + // signal() instead of sigaction() (which would cause |info| to be invalid). + struct sigaction cur_handler; + if (sigaction(sig, NULL, &cur_handler) != 0 || + (cur_handler.sa_flags & SA_SIGINFO) == 0) { + info = NULL; + } + // We served our purpose. Now restore the old crash handlers. If the embedder // did register a custom crash handler, it will be invoked by the kernel after // this function returns. Otherwise, this will end up invoking the default @@ -36,6 +47,17 @@ void AwExceptionHandler(int sig, siginfo_t* info, void* uc) { signal(kExceptionSignals[i], SIG_DFL); } } + + if ((info != NULL && info->si_pid) || sig == SIGABRT) { + // This signal was triggered by somebody sending us the signal with kill(). + // In order to retrigger it, we have to queue a new signal by calling + // kill() ourselves. The special case (si_pid == 0 && sig == SIGABRT) is + // due to the kernel sending a SIGABRT from a user request via SysRQ. + if (syscall(__NR_tgkill, getpid(), syscall(__NR_gettid), sig) < 0) { + // If we failed to kill ourselves resort to terminating uncleanly. + exit(1); + } + } } } // namespace @@ -65,6 +87,7 @@ void RegisterCrashHandler(const std::string& version) { memset(&sa, 0, sizeof(sa)); sigemptyset(&sa.sa_mask); + // Mask all exception signals when we're handling one of them. for (uint32_t i = 0; i < arraysize(kExceptionSignals); ++i) sigaddset(&sa.sa_mask, kExceptionSignals[i]); diff --git a/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java b/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java index a38451d45f801..f13ecac458314 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java +++ b/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java @@ -20,7 +20,8 @@ * Wrapper for the steps needed to initialize the java and native sides of webview chromium. */ public abstract class AwBrowserProcess { - private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "webview"; + public static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "webview"; + private static final String TAG = "AwBrowserProcess"; /** 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 60b976ea868cd..7f0dc03d2026e 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java @@ -276,6 +276,8 @@ private static class FullScreenTransitionsState { private final InternalAccessDelegate mInitialInternalAccessAdapter; private final AwViewMethods mInitialAwViewMethods; private FullScreenView mFullScreenView; + /** Whether the initial container view was focused when we entered fullscreen */ + private boolean mWasInitialContainerViewFocused; private FullScreenTransitionsState(ViewGroup initialContainerView, InternalAccessDelegate initialInternalAccessAdapter, @@ -285,8 +287,14 @@ private FullScreenTransitionsState(ViewGroup initialContainerView, mInitialAwViewMethods = initialAwViewMethods; } - private void enterFullScreen(FullScreenView fullScreenView) { + private void enterFullScreen(FullScreenView fullScreenView, + boolean wasInitialContainerViewFocused) { mFullScreenView = fullScreenView; + mWasInitialContainerViewFocused = wasInitialContainerViewFocused; + } + + private boolean wasInitialContainerViewFocused() { + return mWasInitialContainerViewFocused; } private void exitFullScreen() { @@ -663,8 +671,14 @@ View enterFullScreen() { // In fullscreen mode FullScreenView owns the AwViewMethodsImpl and AwContents // a NullAwViewMethods. - FullScreenView fullScreenView = new FullScreenView(mContext, mAwViewMethods); - mFullScreenTransitionsState.enterFullScreen(fullScreenView); + FullScreenView fullScreenView = new FullScreenView(mContext, mAwViewMethods, this); + fullScreenView.setFocusable(true); + fullScreenView.setFocusableInTouchMode(true); + boolean wasInitialContainerViewFocused = mContainerView.isFocused(); + if (wasInitialContainerViewFocused) { + fullScreenView.requestFocus(); + } + mFullScreenTransitionsState.enterFullScreen(fullScreenView, wasInitialContainerViewFocused); mAwViewMethods = new NullAwViewMethods(this, mInternalAccessAdapter, mContainerView); mContainerView.removeOnLayoutChangeListener(mLayoutChangeListener); fullScreenView.addOnLayoutChangeListener(mLayoutChangeListener); @@ -715,6 +729,10 @@ void exitFullScreen() { setInternalAccessAdapter(mFullScreenTransitionsState.getInitialInternalAccessDelegate()); setContainerView(initialContainerView); + // Return focus to the WebView. + if (mFullScreenTransitionsState.wasInitialContainerViewFocused()) { + mContainerView.requestFocus(); + } mFullScreenTransitionsState.exitFullScreen(); } diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java b/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java index 7800965964bbc..dab4274cd8f1d 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java @@ -81,6 +81,10 @@ public static void registerCrashHandler(String version) { nativeRegisterCrashHandler(version); } + public static void setLegacyCacheRemovalDelayForTest(long timeoutMs) { + nativeSetLegacyCacheRemovalDelayForTest(timeoutMs); + } + //-------------------------------------------------------------------------------------------- // Native methods //-------------------------------------------------------------------------------------------- @@ -90,4 +94,5 @@ public static void registerCrashHandler(String version) { private static native String nativeGetUnreachableWebDataUrl(); private static native void nativeSetRecordFullDocument(boolean recordFullDocument); private static native void nativeRegisterCrashHandler(String version); + private static native void nativeSetLegacyCacheRemovalDelayForTest(long timeoutMs); } diff --git a/android_webview/java/src/org/chromium/android_webview/FullScreenView.java b/android_webview/java/src/org/chromium/android_webview/FullScreenView.java index 3dd0f3d65c4d8..1eb96a4eda3dd 100644 --- a/android_webview/java/src/org/chromium/android_webview/FullScreenView.java +++ b/android_webview/java/src/org/chromium/android_webview/FullScreenView.java @@ -23,11 +23,14 @@ public class FullScreenView extends FrameLayout { private AwViewMethods mAwViewMethods; + private final AwContents mAwContents; private InternalAccessAdapter mInternalAccessAdapter; - public FullScreenView(Context context, AwViewMethods awViewMethods) { + public FullScreenView(Context context, AwViewMethods awViewMethods, + AwContents awContents) { super(context); setAwViewMethods(awViewMethods); + mAwContents = awContents; mInternalAccessAdapter = new InternalAccessAdapter(); } @@ -73,6 +76,12 @@ public boolean onKeyUp(final int keyCode, final KeyEvent event) { @Override public boolean dispatchKeyEvent(final KeyEvent event) { + if (event.getKeyCode() == KeyEvent.KEYCODE_BACK + && event.getAction() == KeyEvent.ACTION_UP + && mAwContents.isFullScreen()) { + mAwContents.requestExitFullscreen(); + return true; + } return mAwViewMethods.dispatchKeyEvent(event); } diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java index 5881f20bc7c15..da731d22f0b2b 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java @@ -5,6 +5,7 @@ package org.chromium.android_webview.test; import android.test.suitebuilder.annotation.MediumTest; +import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; @@ -128,6 +129,37 @@ public void run() { }); } + @MediumTest + @Feature({"AndroidWebView"}) + public void testOnShowAndHideCustomViewWithBackKey_video() throws Throwable { + doTestOnShowAndHideCustomViewWithBackKey(VIDEO_TEST_URL); + } + + @MediumTest + @Feature({"AndroidWebView"}) + public void testOnShowAndHideCustomViewWithBackKey_videoInsideDiv() + throws Throwable { + doTestOnShowAndHideCustomViewWithBackKey(VIDEO_INSIDE_DIV_TEST_URL); + } + + public void doTestOnShowAndHideCustomViewWithBackKey(String videoTestUrl) throws Throwable { + doOnShowCustomViewTest(videoTestUrl); + + // The key event should not be propagated to mTestContainerView (the original container + // view). + mTestContainerView.setOnKeyListener(new View.OnKeyListener() { + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + fail("mTestContainerView received key event"); + return false; + } + }); + + sendKeys(KeyEvent.KEYCODE_BACK); + mContentsClient.waitForCustomViewHidden(); + assertFalse(mContentsClient.wasOnUnhandledKeyUpEventCalled()); + } + @MediumTest @Feature({"AndroidWebView"}) public void testOnShowCustomViewAndPlayWithHtmlControl_video() throws Throwable { 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 2e2c5004e6975..6bcbd446491a9 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 @@ -49,16 +49,20 @@ public AwTestBase() { protected void setUp() throws Exception { super.setUp(); if (needsBrowserProcessStarted()) { - final Context context = getActivity(); - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - AwBrowserProcess.start(context); - } - }); + startBrowserProcess(); } } + protected void startBrowserProcess() throws Exception { + final Context context = getActivity(); + getInstrumentation().runOnMainSync(new Runnable() { + @Override + public void run() { + AwBrowserProcess.start(context); + } + }); + } + /* Override this to return false if the test doesn't want the browser startup sequence to * be run automatically. */ diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/FullScreenVideoTestAwContentsClient.java b/android_webview/javatests/src/org/chromium/android_webview/test/FullScreenVideoTestAwContentsClient.java index 2143c466e904f..6d1c06b1d9790 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/FullScreenVideoTestAwContentsClient.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/FullScreenVideoTestAwContentsClient.java @@ -6,6 +6,7 @@ import android.app.Activity; import android.view.Gravity; +import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; @@ -26,6 +27,7 @@ public class FullScreenVideoTestAwContentsClient extends TestAwContentsClient { public static final long WAITING_SECONDS = scaleTimeout(20); private CallbackHelper mOnShowCustomViewCallbackHelper = new CallbackHelper(); private CallbackHelper mOnHideCustomViewCallbackHelper = new CallbackHelper(); + private CallbackHelper mOnUnhandledKeyUpEventCallbackHelper = new CallbackHelper(); private final Activity mActivity; private final boolean mAllowHardwareAcceleration; @@ -69,6 +71,17 @@ public WebChromeClient.CustomViewCallback getExitCallback() { return mExitCallback; } + @Override + public void onUnhandledKeyEvent(KeyEvent event) { + if (event.getAction() == KeyEvent.ACTION_UP) { + mOnUnhandledKeyUpEventCallbackHelper.notifyCalled(); + } + } + + public boolean wasOnUnhandledKeyUpEventCalled() { + return mOnUnhandledKeyUpEventCallbackHelper.getCallCount() > 0; + } + public View getCustomView() { return mCustomView; } diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/HttpCacheTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/HttpCacheTest.java new file mode 100644 index 0000000000000..8b28508359c76 --- /dev/null +++ b/android_webview/javatests/src/org/chromium/android_webview/test/HttpCacheTest.java @@ -0,0 +1,112 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.android_webview.test; + +import android.test.suitebuilder.annotation.SmallTest; + +import org.chromium.android_webview.AwBrowserProcess; +import org.chromium.android_webview.AwContents; +import org.chromium.android_webview.AwContentsStatics; +import org.chromium.base.PathUtils; +import org.chromium.base.test.util.Feature; +import org.chromium.net.test.util.TestWebServer; + +import java.io.File; + +/** + * Test suite for the HTTP cache. + */ +public class HttpCacheTest extends AwTestBase { + + @Override + protected boolean needsBrowserProcessStarted() { + return false; + } + + @SmallTest + @Feature({"AndroidWebView"}) + public void testHttpCacheIsInsideCacheDir() throws Exception { + File webViewCacheDir = new File( + getInstrumentation().getTargetContext().getCacheDir().getPath(), + "org.chromium.android_webview"); + deleteDirectory(webViewCacheDir); + + startBrowserProcess(); + final TestAwContentsClient contentClient = new TestAwContentsClient(); + final AwTestContainerView testContainerView = + createAwTestContainerViewOnMainSync(contentClient); + final AwContents awContents = testContainerView.getAwContents(); + + TestWebServer httpServer = null; + try { + httpServer = TestWebServer.start(); + final String pageUrl = "/page.html"; + final String pageHtml = "Hello, World!"; + final String fullPageUrl = httpServer.setResponse(pageUrl, pageHtml, null); + loadUrlSync(awContents, contentClient.getOnPageFinishedHelper(), fullPageUrl); + assertEquals(1, httpServer.getRequestCount(pageUrl)); + } finally { + if (httpServer != null) { + httpServer.shutdown(); + } + } + + assertTrue(webViewCacheDir.isDirectory()); + assertTrue(webViewCacheDir.list().length > 0); + } + + private void deleteDirectory(File dir) throws Exception { + if (!dir.exists()) + return; + assertTrue(dir.isDirectory()); + Process rmrf = Runtime.getRuntime().exec("rm -rf " + dir.getAbsolutePath()); + rmrf.waitFor(); + assertFalse(dir.exists()); + } + + @SmallTest + @Feature({"AndroidWebView"}) + public void testLegacyHttpCacheDirIsRemovedOnStartup() throws Exception { + PathUtils.setPrivateDataDirectorySuffix(AwBrowserProcess.PRIVATE_DATA_DIRECTORY_SUFFIX); + File webViewLegacyCacheDir = new File( + PathUtils.getDataDirectory(getInstrumentation().getTargetContext()), "Cache"); + if (!webViewLegacyCacheDir.isDirectory()) { + assertTrue(webViewLegacyCacheDir.mkdir()); + assertTrue(webViewLegacyCacheDir.isDirectory()); + } + File dummyCacheFile = File.createTempFile("test", null, webViewLegacyCacheDir); + assertTrue(dummyCacheFile.exists()); + + // Set up JNI bindings. + AwBrowserProcess.loadLibrary(); + // No delay before removing the legacy cache files. + AwContentsStatics.setLegacyCacheRemovalDelayForTest(0); + + startBrowserProcess(); + final TestAwContentsClient contentClient = new TestAwContentsClient(); + final AwTestContainerView testContainerView = + createAwTestContainerViewOnMainSync(contentClient); + final AwContents awContents = testContainerView.getAwContents(); + + // Do some page loading to make sure that FILE thread has processed + // our directory removal task. + TestWebServer httpServer = null; + try { + httpServer = TestWebServer.start(); + final String pageUrl = "/page.html"; + final String pageHtml = "Hello, World!"; + final String fullPageUrl = httpServer.setResponse(pageUrl, pageHtml, null); + loadUrlSync(awContents, contentClient.getOnPageFinishedHelper(), fullPageUrl); + assertEquals(1, httpServer.getRequestCount(pageUrl)); + } finally { + if (httpServer != null) { + httpServer.shutdown(); + } + } + + assertFalse(webViewLegacyCacheDir.exists()); + assertFalse(dummyCacheFile.exists()); + } +} diff --git a/android_webview/native/aw_contents_statics.cc b/android_webview/native/aw_contents_statics.cc index ee61de6fa134a..e09fcb8c61dd7 100644 --- a/android_webview/native/aw_contents_statics.cc +++ b/android_webview/native/aw_contents_statics.cc @@ -96,6 +96,11 @@ void RegisterCrashHandler(JNIEnv* env, jclass, jstring version) { ConvertJavaStringToUTF8(env, version)); } +// static +void SetLegacyCacheRemovalDelayForTest(JNIEnv*, jclass, jlong delay_ms) { + AwBrowserContext::SetLegacyCacheRemovalDelayForTest(delay_ms); +} + bool RegisterAwContentsStatics(JNIEnv* env) { return RegisterNativesImpl(env); } diff --git a/apps/app_lifetime_monitor.cc b/apps/app_lifetime_monitor.cc index 16323e9f4872f..3190e290fa5e5 100644 --- a/apps/app_lifetime_monitor.cc +++ b/apps/app_lifetime_monitor.cc @@ -81,21 +81,24 @@ void AppLifetimeMonitor::Observe(int type, } void AppLifetimeMonitor::OnAppWindowRemoved(AppWindow* app_window) { - if (!HasVisibleAppWindows(app_window)) + if (!HasOtherVisibleAppWindows(app_window)) NotifyAppDeactivated(app_window->extension_id()); } void AppLifetimeMonitor::OnAppWindowHidden(AppWindow* app_window) { - if (!HasVisibleAppWindows(app_window)) + if (!HasOtherVisibleAppWindows(app_window)) NotifyAppDeactivated(app_window->extension_id()); } -void AppLifetimeMonitor::OnAppWindowShown(AppWindow* app_window) { +void AppLifetimeMonitor::OnAppWindowShown(AppWindow* app_window, + bool was_hidden) { if (app_window->window_type() != AppWindow::WINDOW_TYPE_DEFAULT) return; - if (HasVisibleAppWindows(app_window)) + // The app is being activated if this is the first window to become visible. + if (was_hidden && !HasOtherVisibleAppWindows(app_window)) { NotifyAppActivated(app_window->extension_id()); + } } void AppLifetimeMonitor::Shutdown() { @@ -106,7 +109,8 @@ void AppLifetimeMonitor::Shutdown() { app_window_registry->RemoveObserver(this); } -bool AppLifetimeMonitor::HasVisibleAppWindows(AppWindow* app_window) const { +bool AppLifetimeMonitor::HasOtherVisibleAppWindows( + AppWindow* app_window) const { AppWindowRegistry::AppWindowList windows = AppWindowRegistry::Get(app_window->browser_context()) ->GetAppWindowsForApp(app_window->extension_id()); @@ -114,7 +118,7 @@ bool AppLifetimeMonitor::HasVisibleAppWindows(AppWindow* app_window) const { for (AppWindowRegistry::AppWindowList::const_iterator i = windows.begin(); i != windows.end(); ++i) { - if (!(*i)->is_hidden()) + if (*i != app_window && !(*i)->is_hidden()) return true; } return false; diff --git a/apps/app_lifetime_monitor.h b/apps/app_lifetime_monitor.h index 8f079feb9b155..90ae2a8d8496f 100644 --- a/apps/app_lifetime_monitor.h +++ b/apps/app_lifetime_monitor.h @@ -32,9 +32,11 @@ class AppLifetimeMonitor : public KeyedService, public: // Called when the app starts running. virtual void OnAppStart(Profile* profile, const std::string& app_id) {} - // Called when the app becomes active to the user, i.e. it opens a window. + // Called when the app becomes active to the user, i.e. the first window + // becomes visible. virtual void OnAppActivated(Profile* profile, const std::string& app_id) {} - // Called when the app becomes inactive to the user. + // Called when the app becomes inactive to the user, i.e. the last window is + // hidden or closed. virtual void OnAppDeactivated(Profile* profile, const std::string& app_id) { } // Called when the app stops running. @@ -63,12 +65,13 @@ class AppLifetimeMonitor : public KeyedService, // extensions::AppWindowRegistry::Observer overrides: void OnAppWindowRemoved(extensions::AppWindow* app_window) override; void OnAppWindowHidden(extensions::AppWindow* app_window) override; - void OnAppWindowShown(extensions::AppWindow* app_window) override; + void OnAppWindowShown(extensions::AppWindow* app_window, + bool was_hidden) override; // KeyedService overrides: void Shutdown() override; - bool HasVisibleAppWindows(extensions::AppWindow* app_window) const; + bool HasOtherVisibleAppWindows(extensions::AppWindow* app_window) const; void NotifyAppStart(const std::string& app_id); void NotifyAppActivated(const std::string& app_id); diff --git a/base/android/java/src/org/chromium/base/ApplicationStatus.java b/base/android/java/src/org/chromium/base/ApplicationStatus.java index af02ea23d15e8..ce294bc5a5dda 100644 --- a/base/android/java/src/org/chromium/base/ApplicationStatus.java +++ b/base/android/java/src/org/chromium/base/ApplicationStatus.java @@ -109,11 +109,11 @@ private ApplicationStatus() {} * * @param application The application whose status you wish to monitor. */ - public static void initialize(BaseChromiumApplication application) { - sApplication = application; + public static void initialize(Application app) { + sApplication = app; - application.registerWindowFocusChangedListener( - new BaseChromiumApplication.WindowFocusChangedListener() { + ApplicationStatusManager.registerWindowFocusChangedListener( + new ApplicationStatusManager.WindowFocusChangedListener() { @Override public void onWindowFocusChanged(Activity activity, boolean hasFocus) { if (!hasFocus || activity == sActivity) return; @@ -128,7 +128,7 @@ public void onWindowFocusChanged(Activity activity, boolean hasFocus) { } }); - application.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { + sApplication.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { @Override public void onActivityCreated(final Activity activity, Bundle savedInstanceState) { onStateChange(activity, ActivityState.CREATED); @@ -193,6 +193,9 @@ private static void onStateChange(Activity activity, int newState) { } ActivityInfo info = sActivityInfo.get(activity); + // Ignore status from none tracked activitys. + if (info == null) return; + info.setStatus(newState); // Notify all state observers that are specifically listening to this activity. @@ -388,6 +391,17 @@ public static void unregisterApplicationStateListener(ApplicationStateListener l sApplicationStateListeners.removeObserver(listener); } + /** + * When ApplicationStatus initialized after application started, the onActivityCreated(), + * onActivityStarted() and onActivityResumed() callbacks will be missed. + * This function will give the chance to simulate these three callbacks. + */ + public static void informActivityStarted(Activity activity) { + onStateChange(activity, ActivityState.CREATED); + onStateChange(activity, ActivityState.STARTED); + onStateChange(activity, ActivityState.RESUMED); + } + /** * Registers the single thread-safe native activity status listener. * This handles the case where the caller is not on the main thread. diff --git a/base/android/java/src/org/chromium/base/ApplicationStatusManager.java b/base/android/java/src/org/chromium/base/ApplicationStatusManager.java new file mode 100644 index 0000000000000..aeae40f2b53e3 --- /dev/null +++ b/base/android/java/src/org/chromium/base/ApplicationStatusManager.java @@ -0,0 +1,111 @@ +// 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. + +package org.chromium.base; + +import android.app.Activity; +import android.app.Application; +import android.os.Bundle; +import android.view.Window; + +/** + * Basic application functionality that should be shared among all browser applications. + */ +public class ApplicationStatusManager { + /** + * Interface to be implemented by listeners for window focus events. + */ + public interface WindowFocusChangedListener { + /** + * Called when the window focus changes for {@code activity}. + * @param activity The {@link Activity} that has a window focus changed event. + * @param hasFocus Whether or not {@code activity} gained or lost focus. + */ + public void onWindowFocusChanged(Activity activity, boolean hasFocus); + } + + private static ObserverList sWindowFocusListeners = + new ObserverList(); + + public static void init(Application app) { + ApplicationStatus.initialize(app); + + app.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() { + @Override + public void onActivityCreated(final Activity activity, Bundle savedInstanceState) { + setWindowFocusChangedCallback(activity); + } + + @Override + public void onActivityDestroyed(Activity activity) { + assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper; + } + + @Override + public void onActivityPaused(Activity activity) { + assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper; + } + + @Override + public void onActivityResumed(Activity activity) { + assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper; + } + + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle outState) { + assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper; + } + + @Override + public void onActivityStarted(Activity activity) { + assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper; + } + + @Override + public void onActivityStopped(Activity activity) { + assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper; + } + }); + } + + /** + * Registers a listener to receive window focus updates on activities in this application. + * @param listener Listener to receive window focus events. + */ + public static void registerWindowFocusChangedListener(WindowFocusChangedListener listener) { + sWindowFocusListeners.addObserver(listener); + } + + /** + * Unregisters a listener from receiving window focus updates on activities in this application. + * @param listener Listener that doesn't want to receive window focus events. + */ + public static void unregisterWindowFocusChangedListener(WindowFocusChangedListener listener) { + sWindowFocusListeners.removeObserver(listener); + } + + /** + * When ApplicationStatus initialized after application started, the onActivityCreated(), + * onActivityStarted() and onActivityResumed() callbacks will be missed. + * This function will give the chance to simulate these three callbacks. + */ + public static void informActivityStarted(final Activity activity) { + setWindowFocusChangedCallback(activity); + ApplicationStatus.informActivityStarted(activity); + } + + private static void setWindowFocusChangedCallback(final Activity activity) { + Window.Callback callback = activity.getWindow().getCallback(); + activity.getWindow().setCallback(new WindowCallbackWrapper(callback) { + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + + for (WindowFocusChangedListener listener : sWindowFocusListeners) { + listener.onWindowFocusChanged(activity, hasFocus); + } + } + }); + } +} diff --git a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java index a9dc2f783ead8..055fa3e86c24f 100644 --- a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java +++ b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java @@ -4,96 +4,16 @@ package org.chromium.base; -import android.app.Activity; import android.app.Application; -import android.os.Bundle; -import android.view.Window; /** * Basic application functionality that should be shared among all browser applications. */ public class BaseChromiumApplication extends Application { - /** - * Interface to be implemented by listeners for window focus events. - */ - public interface WindowFocusChangedListener { - /** - * Called when the window focus changes for {@code activity}. - * @param activity The {@link Activity} that has a window focus changed event. - * @param hasFocus Whether or not {@code activity} gained or lost focus. - */ - public void onWindowFocusChanged(Activity activity, boolean hasFocus); - } - - private ObserverList mWindowFocusListeners = - new ObserverList(); @Override public void onCreate() { super.onCreate(); - ApplicationStatus.initialize(this); - - registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { - @Override - public void onActivityCreated(final Activity activity, Bundle savedInstanceState) { - Window.Callback callback = activity.getWindow().getCallback(); - activity.getWindow().setCallback(new WindowCallbackWrapper(callback) { - @Override - public void onWindowFocusChanged(boolean hasFocus) { - super.onWindowFocusChanged(hasFocus); - - for (WindowFocusChangedListener listener : mWindowFocusListeners) { - listener.onWindowFocusChanged(activity, hasFocus); - } - } - }); - } - - @Override - public void onActivityDestroyed(Activity activity) { - assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper; - } - - @Override - public void onActivityPaused(Activity activity) { - assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper; - } - - @Override - public void onActivityResumed(Activity activity) { - assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper; - } - - @Override - public void onActivitySaveInstanceState(Activity activity, Bundle outState) { - assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper; - } - - @Override - public void onActivityStarted(Activity activity) { - assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper; - } - - @Override - public void onActivityStopped(Activity activity) { - assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper; - } - }); - } - - /** - * Registers a listener to receive window focus updates on activities in this application. - * @param listener Listener to receive window focus events. - */ - public void registerWindowFocusChangedListener(WindowFocusChangedListener listener) { - mWindowFocusListeners.addObserver(listener); - } - - /** - * Unregisters a listener from receiving window focus updates on activities in this application. - * @param listener Listener that doesn't want to receive window focus events. - */ - public void unregisterWindowFocusChangedListener(WindowFocusChangedListener listener) { - mWindowFocusListeners.removeObserver(listener); + ApplicationStatusManager.init(this); } } diff --git a/base/android/java/src/org/chromium/base/ResourceExtractor.java b/base/android/java/src/org/chromium/base/ResourceExtractor.java index 37fea6c863de3..2ee728d54a186 100644 --- a/base/android/java/src/org/chromium/base/ResourceExtractor.java +++ b/base/android/java/src/org/chromium/base/ResourceExtractor.java @@ -21,6 +21,7 @@ import java.io.OutputStream; import java.util.ArrayList; import java.util.HashSet; +import java.util.Set; import java.util.List; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; @@ -40,12 +41,18 @@ public class ResourceExtractor { private static final String V8_SNAPSHOT_DATA_FILENAME = "snapshot_blob.bin"; private static String[] sMandatoryPaks = null; + private static ResourceIntercepter sIntercepter = null; // By default, we attempt to extract a pak file for the users // current device locale. Use setExtractImplicitLocale() to // change this behavior. private static boolean sExtractImplicitLocalePak = true; + public interface ResourceIntercepter { + Set getInterceptableResourceList(); + InputStream interceptLoadingForResource(String resource); + } + private class ExtractTask extends AsyncTask { private static final int BUFFER_SIZE = 16 * 1024; @@ -65,7 +72,8 @@ protected Void doInBackground(Void... unused) { deleteFiles(); } - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences( + mContext.getApplicationContext()); HashSet filenames = (HashSet) prefs.getStringSet( PAK_FILENAMES, new HashSet()); String currentLocale = LocaleUtils.getDefaultLocale(); @@ -109,6 +117,18 @@ protected Void doInBackground(Void... unused) { // created above. byte[] buffer = null; String[] files = manager.list(""); + if (sIntercepter != null) { + Set filesIncludingInterceptableFiles = + sIntercepter.getInterceptableResourceList(); + if (filesIncludingInterceptableFiles != null && + !filesIncludingInterceptableFiles.isEmpty()) { + for (String file : files) { + filesIncludingInterceptableFiles.add(file); + } + files = new String[filesIncludingInterceptableFiles.size()]; + filesIncludingInterceptableFiles.toArray(files); + } + } for (String file : files) { if (!paksToInstall.matcher(file).matches()) { continue; @@ -125,7 +145,10 @@ protected Void doInBackground(Void... unused) { InputStream is = null; OutputStream os = null; try { - is = manager.open(file); + if (sIntercepter != null) { + is = sIntercepter.interceptLoadingForResource(file); + } + if (is == null) is = manager.open(file); os = new FileOutputStream(output); Log.i(LOGTAG, "Extracting resource " + file); if (buffer == null) { @@ -260,6 +283,19 @@ public static void setMandatoryPaksToExtract(String... mandatoryPaks) { } + /** + * Allow embedders to intercept the resource loading process. Embedders may + * want to load paks from res/raw instead of assets, since assets are not + * supported in Android library project. + * @param intercepter The instance of intercepter which provides the files list + * to intercept and the inputstream for the files it wants to intercept with. + */ + public static void setResourceIntercepter(ResourceIntercepter intercepter) { + assert (sInstance == null || sInstance.mExtractTask == null) + : "Must be called before startExtractingResources is called"; + sIntercepter = intercepter; + } + /** * By default the ResourceExtractor will attempt to extract a pak resource for the users * currently specified locale. This behavior can be changed with this function and is @@ -310,6 +346,10 @@ public void waitForCompletion() { try { mExtractTask.get(); + // ResourceExtractor is not needed any more. + // Release static objects to avoid leak of Context. + sIntercepter = null; + sInstance = null; } catch (CancellationException e) { // Don't leave the files in an inconsistent state. deleteFiles(); diff --git a/base/android/java/src/org/chromium/base/SystemMessageHandler.java b/base/android/java/src/org/chromium/base/SystemMessageHandler.java index 10f8d55448e01..fd3dc5a08b640 100644 --- a/base/android/java/src/org/chromium/base/SystemMessageHandler.java +++ b/base/android/java/src/org/chromium/base/SystemMessageHandler.java @@ -5,12 +5,9 @@ package org.chromium.base; import android.os.Handler; -import android.os.Looper; import android.os.Message; -import android.os.MessageQueue; import android.util.Log; -import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -25,23 +22,31 @@ class SystemMessageHandler extends Handler { private long mMessagePumpDelegateNative = 0; private long mDelayedScheduledTimeTicks = 0; - // The following members are used to detect and trace the presence of sync - // barriers in Android's MessageQueue. Note that this detection is - // experimental, temporary and intended only for diagnostic purposes. - private MessageQueue mMessageQueue; - private Field mMessageQueueMessageField; - private Field mMessageTargetField; - private boolean mQueueHasSyncBarrier; - private long mSyncBarrierTraceId; + // Reflected API for marking a message as asynchronous. This is a workaround + // to provide fair Chromium task dispatch when served by the Android UI + // thread's Looper, avoiding stalls when the Looper has a sync barrier. + // Note: Use of this API is experimental and likely to evolve in the future. + private Method mMessageMethodSetAsynchronous; private SystemMessageHandler(long messagePumpDelegateNative) { mMessagePumpDelegateNative = messagePumpDelegateNative; - tryEnableSyncBarrierDetection(); + + try { + Class messageClass = Class.forName("android.os.Message"); + mMessageMethodSetAsynchronous = messageClass.getMethod( + "setAsynchronous", new Class[]{boolean.class}); + } catch (ClassNotFoundException e) { + Log.e(TAG, "Failed to find android.os.Message class:" + e); + } catch (NoSuchMethodException e) { + Log.e(TAG, "Failed to load Message.setAsynchronous method:" + e); + } catch (RuntimeException e) { + Log.e(TAG, "Exception while loading Message.setAsynchronous method: " + e); + } + } @Override public void handleMessage(Message msg) { - updateWhetherQueueHasBlockingSyncBarrier(); if (msg.what == DELAYED_SCHEDULED_WORK) { mDelayedScheduledTimeTicks = 0; } @@ -51,9 +56,7 @@ public void handleMessage(Message msg) { @SuppressWarnings("unused") @CalledByNative private void scheduleWork() { - updateWhetherQueueHasBlockingSyncBarrier(); - if (mQueueHasSyncBarrier) TraceEvent.instant("SystemMessageHandler:immediateWorkBlocked"); - sendEmptyMessage(SCHEDULED_WORK); + sendMessage(obtainAsyncMessage(SCHEDULED_WORK)); } @SuppressWarnings("unused") @@ -63,97 +66,39 @@ private void scheduleDelayedWork(long delayedTimeTicks, long millis) { removeMessages(DELAYED_SCHEDULED_WORK); } mDelayedScheduledTimeTicks = delayedTimeTicks; - updateWhetherQueueHasBlockingSyncBarrier(); - if (mQueueHasSyncBarrier) TraceEvent.instant("SystemMessageHandler:delayedWorkBlocked"); - sendEmptyMessageDelayed(DELAYED_SCHEDULED_WORK, millis); + sendMessageDelayed(obtainAsyncMessage(DELAYED_SCHEDULED_WORK), millis); } @SuppressWarnings("unused") @CalledByNative private void removeAllPendingMessages() { - updateWhetherQueueHasBlockingSyncBarrier(); removeMessages(SCHEDULED_WORK); removeMessages(DELAYED_SCHEDULED_WORK); } - private void updateWhetherQueueHasBlockingSyncBarrier() { - if (mMessageQueue == null) return; - // As barrier detection is only used for tracing, early out when tracing - // is disabled to avoid any potential performance penalties. - if (!TraceEvent.enabled()) { - mQueueHasSyncBarrier = false; - return; - } - Message queueHead = (Message) getField(mMessageQueue, mMessageQueueMessageField); - setqueueHasSyncBarrier(isSyncBarrierMessage(queueHead)); - } - - private boolean isSyncBarrierMessage(Message message) { - if (message == null) return false; - // Sync barrier messages have null targets. - return getField(message, mMessageTargetField) == null; - } - - private void tryEnableSyncBarrierDetection() { - assert mMessageQueue == null; - - boolean success = false; - try { - Method getQueueMethod = Looper.class.getMethod("getQueue", new Class[]{}); - mMessageQueue = (MessageQueue) getQueueMethod.invoke(getLooper()); - - mMessageQueueMessageField = mMessageQueue.getClass().getDeclaredField("mMessages"); - mMessageQueueMessageField.setAccessible(true); - - mMessageTargetField = Message.class.getDeclaredField("target"); - mMessageTargetField.setAccessible(true); - - mSyncBarrierTraceId = hashCode(); - - success = true; - } catch (NoSuchMethodException e) { - Log.e(TAG, "Failed to load method: " + e); - } catch (NoSuchFieldException e) { - Log.e(TAG, "Failed to load field: " + e); - } catch (InvocationTargetException e) { - Log.e(TAG, "Failed invocation: " + e); - } catch (IllegalAccessException e) { - Log.e(TAG, "Illegal access to reflected invocation: " + e); - } catch (IllegalArgumentException e) { - Log.e(TAG, "Illegal argument to reflected invocation: " + e); - } catch (RuntimeException e) { - Log.e(TAG, e.toString()); - } finally { - if (!success) disableSyncBarrierDetection(); - } - } - - private void disableSyncBarrierDetection() { - Log.e(TAG, "Unexpected error with sync barrier detection, disabling."); - mMessageQueue = null; - mMessageQueueMessageField = null; - mMessageTargetField = null; - setqueueHasSyncBarrier(false); - } - - private void setqueueHasSyncBarrier(boolean queueHasSyncBarrier) { - if (queueHasSyncBarrier == mQueueHasSyncBarrier) return; - mQueueHasSyncBarrier = queueHasSyncBarrier; - if (mQueueHasSyncBarrier) { - TraceEvent.startAsync("SyncBarrier", mSyncBarrierTraceId); - } else { - TraceEvent.finishAsync("SyncBarrier", mSyncBarrierTraceId); - } - } - - private Object getField(Object object, Field field) { - try { - return field.get(object); - } catch (IllegalAccessException e) { - Log.e(TAG, "Failed field access: " + e); - disableSyncBarrierDetection(); + private Message obtainAsyncMessage(int what) { + Message msg = Message.obtain(); + msg.what = what; + if (mMessageMethodSetAsynchronous != null) { + // If invocation fails, assume this is indicative of future + // failures, and avoid log spam by nulling the reflected method. + try { + mMessageMethodSetAsynchronous.invoke(msg, true); + } catch (IllegalAccessException e) { + Log.e(TAG, "Illegal access to asynchronous message creation, disabling."); + mMessageMethodSetAsynchronous = null; + } catch (IllegalArgumentException e) { + Log.e(TAG, "Illegal argument for asynchronous message creation, disabling."); + mMessageMethodSetAsynchronous = null; + } catch (InvocationTargetException e) { + Log.e(TAG, "Invocation exception during asynchronous message creation, disabling."); + mMessageMethodSetAsynchronous = null; + } catch (RuntimeException e) { + Log.e(TAG, "Runtime exception during asynchronous message creation, disabling."); + mMessageMethodSetAsynchronous = null; + } } - return null; + return msg; } @CalledByNative diff --git a/base/base.gyp b/base/base.gyp index ad4dd22679285..49d508f9d90e9 100644 --- a/base/base.gyp +++ b/base/base.gyp @@ -54,7 +54,7 @@ ['exclude', '_nss\\.cc$'], ], }], - ['use_glib==1', { + ['use_glib==1 or <(use_ozone)==1', { 'dependencies': [ '../build/linux/system.gyp:glib', ], diff --git a/base/base.gypi b/base/base.gypi index 416a7e5aa6ee7..9ef1a738787e3 100644 --- a/base/base.gypi +++ b/base/base.gypi @@ -752,7 +752,7 @@ 'atomicops_internals_x86_gcc.cc', ], }], - ['<(use_glib)==0 or >(nacl_untrusted_build)==1', { + ['(<(use_glib)==0 and <(use_ozone)==0) or >(nacl_untrusted_build)==1', { 'sources!': [ 'message_loop/message_pump_glib.cc', ], @@ -934,11 +934,6 @@ 'strings/string16.cc', ], },], - ['<(use_ozone) == 1', { - 'sources!': [ - 'message_loop/message_pump_glib.cc', - ] - }], ['OS == "linux" and >(nacl_untrusted_build)==0', { 'sources!': [ 'files/file_path_watcher_fsevents.cc', diff --git a/base/files/file_unittest.cc b/base/files/file_unittest.cc index 9f57974d8cb41..3bc2db60f0e4f 100644 --- a/base/files/file_unittest.cc +++ b/base/files/file_unittest.cc @@ -476,7 +476,7 @@ TEST(FileTest, MemoryCorruption) { EXPECT_NE(file.file_.file_memory_checksum_, implicit_cast(file.GetPlatformFile())); file.file_.file_memory_checksum_ = file.GetPlatformFile(); - EXPECT_DEATH(file.IsValid(), "corrupted fd memory"); + EXPECT_DEATH(file.IsValid(), ""); file.file_.UpdateChecksum(); // Do not crash on File::~File(). } @@ -485,7 +485,7 @@ TEST(FileTest, MemoryCorruption) { // Test that changing the file descriptor value is detected. base::File file; file.file_.file_.reset(17); - EXPECT_DEATH(file.IsValid(), "corrupted fd memory"); + EXPECT_DEATH(file.IsValid(), ""); // Do not crash on File::~File(). ignore_result(file.file_.file_.release()); @@ -496,7 +496,7 @@ TEST(FileTest, MemoryCorruption) { // Test that GetPlatformFile() checks for corruption. base::File file; file.file_.file_memory_checksum_ = file.GetPlatformFile(); - EXPECT_DEATH(file.GetPlatformFile(), "corrupted fd memory"); + EXPECT_DEATH(file.GetPlatformFile(), ""); file.file_.UpdateChecksum(); // Do not crash on File::~File(). } @@ -505,7 +505,7 @@ TEST(FileTest, MemoryCorruption) { // Test that the base::File destructor checks for corruption. scoped_ptr file(new File()); file->file_.file_memory_checksum_ = file->GetPlatformFile(); - EXPECT_DEATH(file.reset(), "corrupted fd memory"); + EXPECT_DEATH(file.reset(), ""); // Do not crash on this thread's destructor call. file->file_.UpdateChecksum(); @@ -515,7 +515,7 @@ TEST(FileTest, MemoryCorruption) { // Test that the base::File constructor checks for corruption. base::File file; file.file_.file_memory_checksum_ = file.GetPlatformFile(); - EXPECT_DEATH(File f(file.Pass()), "corrupted fd memory"); + EXPECT_DEATH(File f(file.Pass()), ""); file.file_.UpdateChecksum(); // Do not crash on File::~File(). } @@ -525,10 +525,10 @@ TEST(FileTest, MemoryCorruption) { base::File file; file.file_.file_.reset(17); // A fake open FD value. - EXPECT_DEATH(file.Seek(File::FROM_BEGIN, 0), "corrupted fd memory"); - EXPECT_DEATH(file.Read(0, NULL, 0), "corrupted fd memory"); - EXPECT_DEATH(file.ReadAtCurrentPos(NULL, 0), "corrupted fd memory"); - EXPECT_DEATH(file.Write(0, NULL, 0), "corrupted fd memory"); + EXPECT_DEATH(file.Seek(File::FROM_BEGIN, 0), ""); + EXPECT_DEATH(file.Read(0, NULL, 0), ""); + EXPECT_DEATH(file.ReadAtCurrentPos(NULL, 0), ""); + EXPECT_DEATH(file.Write(0, NULL, 0), ""); ignore_result(file.file_.file_.release()); file.file_.UpdateChecksum(); diff --git a/base/threading/thread_local.h b/base/threading/thread_local.h index df9c4b72573be..b6bfb8a2dd9d5 100644 --- a/base/threading/thread_local.h +++ b/base/threading/thread_local.h @@ -80,6 +80,7 @@ struct BASE_EXPORT ThreadLocalPlatform { } // namespace internal +#if !defined(OS_ANDROID) template class ThreadLocalPointer { public: @@ -108,6 +109,28 @@ class ThreadLocalPointer { DISALLOW_COPY_AND_ASSIGN(ThreadLocalPointer); }; +#else +template + class ThreadLocalPointer { + public: + ThreadLocalPointer() {} + + ~ThreadLocalPointer() { slot_.Free(); } + + Type* Get() { + return static_cast(slot_.Get()); + } + + void Set(Type* ptr) { + slot_.Set(const_cast(static_cast(ptr))); + } + + private: + ThreadLocalStorage::Slot slot_; + + DISALLOW_COPY_AND_ASSIGN(ThreadLocalPointer); +}; +#endif // !OS_ANDROID class ThreadLocalBoolean { public: diff --git a/base/time/time.h b/base/time/time.h index 641f465af3e47..9cb007ec222b3 100644 --- a/base/time/time.h +++ b/base/time/time.h @@ -232,6 +232,10 @@ class BASE_EXPORT Time { static const int64 kNanosecondsPerSecond = kNanosecondsPerMicrosecond * kMicrosecondsPerSecond; + // The representation of Jan 1, 1970 UTC in microseconds since the + // platform-dependent epoch. + static const int64 kTimeTToMicrosecondsOffset; + #if !defined(OS_WIN) // On Mac & Linux, this value is the delta from the Windows epoch of 1601 to // the Posix delta of 1970. This is used for migrating between the old @@ -492,10 +496,6 @@ class BASE_EXPORT Time { bool is_local, Time* parsed_time); - // The representation of Jan 1, 1970 UTC in microseconds since the - // platform-dependent epoch. - static const int64 kTimeTToMicrosecondsOffset; - // Time in microseconds in UTC. int64 us_; }; diff --git a/build/android/adb_install_apk.py b/build/android/adb_install_apk.py index 5d0fd17149409..ac6e505609873 100755 --- a/build/android/adb_install_apk.py +++ b/build/android/adb_install_apk.py @@ -9,6 +9,7 @@ import optparse import os import sys +import time from pylib import android_commands from pylib import constants @@ -71,13 +72,25 @@ def main(argv): constants.SetBuildType(options.build_type) ValidateInstallAPKOption(parser, options, args) - devices = android_commands.GetAttachedDevices() - - if options.device: - if options.device not in devices: - raise Exception('Error: %s not in attached devices %s' % (options.device, - ','.join(devices))) - devices = [options.device] + retry_times = 5 + retry_interval = 15 + while retry_times > 0: + devices = android_commands.GetAttachedDevices() + if options.device: + if options.device not in devices: + raise Exception('Error: %s not in attached devices %s' % \ + (options.device, ','.join(devices))) + devices = [options.device] + + if not devices: + print 'No connected devices found, '\ + 'kill adb server and retry in %d seconds...' % retry_interval + android_commands.AndroidCommands().KillAdbServer() + time.sleep(retry_interval) + retry_interval *= 2 + retry_times -= 1 + else: + break if not devices: raise Exception('Error: no connected devices') diff --git a/build/android/pylib/android_commands.py b/build/android/pylib/android_commands.py index ea86e6d90176b..979e9fce41b69 100644 --- a/build/android/pylib/android_commands.py +++ b/build/android/pylib/android_commands.py @@ -511,8 +511,10 @@ def Install(self, package_file_path, reinstall=False): install_cmd = ' '.join(install_cmd) self._LogShell(install_cmd) + # FIXME(wang16): Change the timeout here to five minutes. Revert + # the change when slaves can run kvm enabled x86 android emulators. return self._adb.SendCommand(install_cmd, - timeout_time=2 * 60, + timeout_time=5 * 60, retry_count=0) def ManagedInstall(self, apk_path, keep_data=False, package_name=None, diff --git a/build/android/pylib/utils/isolator.py b/build/android/pylib/utils/isolator.py index 9ee5671acab51..afbee2a8305c0 100644 --- a/build/android/pylib/utils/isolator.py +++ b/build/android/pylib/utils/isolator.py @@ -32,7 +32,6 @@ def DefaultConfigVariables(): 'component': 'static_library', 'fastbuild': '0', 'icu_use_data_file_flag': '1', - 'libpeer_target_type': 'static_library', 'lsan': '0', # TODO(maruel): This may not always be true. 'target_arch': 'arm', diff --git a/build/common.gypi b/build/common.gypi index f79230350ff44..bb6165c15d5e4 100644 --- a/build/common.gypi +++ b/build/common.gypi @@ -1510,9 +1510,6 @@ 'ozone_platform_ozonex%': 0, 'ozone_platform_test%': 0, - # Whether the browser is non-native (using Views Toolkit) on Mac. - 'mac_views_browser%': 0, - 'conditions': [ ['buildtype=="Official"', { # Continue to embed build meta data in Official builds, basically the @@ -2403,6 +2400,10 @@ # Whether to allow building of chromoting related isolates. 'archive_chromoting_tests%': 0, + + # Flags to enable Murphy resource policy daemon integration on Tizen. + 'tizen%': 0, + 'enable_murphy%': 0, }, 'target_defaults': { 'variables': { diff --git a/build/config/features.gni b/build/config/features.gni index a395b406c977e..5060d5e4e1d37 100644 --- a/build/config/features.gni +++ b/build/config/features.gni @@ -77,9 +77,8 @@ enable_print_preview = !is_android use_seccomp_bpf = (is_linux || is_android) && (cpu_arch == "x86" || cpu_arch == "x64" || cpu_arch == "arm") -# Enable notifications everywhere except Android/iOS. -# Android is http://crbug.com/115320 -enable_notifications = !is_android && !is_ios +# Enable notifications everywhere except iOS. +enable_notifications = !is_ios # TODO(brettw) this should be moved to net and only dependents get this define. disable_ftp_support = is_ios diff --git a/build/linux/system.gyp b/build/linux/system.gyp index 3e880939f8444..478885af8ae30 100644 --- a/build/linux/system.gyp +++ b/build/linux/system.gyp @@ -1080,5 +1080,27 @@ }], ], }, + { + 'target_name': 'resource_manager', + 'type': 'none', + 'toolsets': ['host', 'target'], + 'conditions': [ + ['tizen==1 and enable_murphy==1', { + 'direct_dependent_settings': { + 'cflags': [ + ' to_erase; int min_toss_x = tiling_.num_tiles_x(); - if (tiling_size().width() > old_tiling_size.width()) { + if (max_tiling_size.width() > min_tiling_size.width()) { min_toss_x = - tiling_.FirstBorderTileXIndexFromSrcCoord(old_tiling_size.width()); + tiling_.FirstBorderTileXIndexFromSrcCoord(min_tiling_size.width()); } int min_toss_y = tiling_.num_tiles_y(); - if (tiling_size().height() > old_tiling_size.height()) { + if (max_tiling_size.height() > min_tiling_size.height()) { min_toss_y = - tiling_.FirstBorderTileYIndexFromSrcCoord(old_tiling_size.height()); + tiling_.FirstBorderTileYIndexFromSrcCoord(min_tiling_size.height()); } for (PictureMap::const_iterator it = picture_map_.begin(); it != picture_map_.end(); @@ -221,20 +230,22 @@ bool PicturePile::UpdateAndExpandInvalidation( // If a recording is dropped and not re-recorded below, invalidate that // full recording to cause any raster tiles that would use it to be // dropped. - // If the recording will be replaced below, just invalidate newly exposed - // areas to force raster tiles that include the old recording to know - // there is new recording to display. - gfx::Rect old_tiling_rect_over_tiles = - tiling_.ExpandRectToTileBounds(gfx::Rect(old_tiling_size)); + // If the recording will be replaced below, invalidate newly exposed + // areas and previously exposed areas to force raster tiles that include the + // old recording to know there is new recording to display. + gfx::Rect min_tiling_rect_over_tiles = + tiling_.ExpandRectToTileBounds(gfx::Rect(min_tiling_size)); if (min_toss_x < tiling_.num_tiles_x()) { // The bounds which we want to invalidate are the tiles along the old - // edge of the pile. We'll call this bounding box the OLD EDGE RECT. + // edge of the pile when expanding, or the new edge of the pile when + // shrinking. In either case, it's the difference of the two, so we'll + // call this bounding box the DELTA EDGE RECT. // - // In the picture below, the old edge rect would be the bounding box - // of tiles {h,i,j}. |min_toss_x| would be equal to the horizontal index - // of the same tiles. + // In the picture below, the delta edge rect would be the bounding box of + // tiles {h,i,j}. |min_toss_x| would be equal to the horizontal index of + // the same tiles. // - // old pile edge-v new pile edge-v + // min pile edge-v max pile edge-v // ---------------+ - - - - - - - -+ // mmppssvvyybbeeh|h . // mmppssvvyybbeeh|h . @@ -242,33 +253,33 @@ bool PicturePile::UpdateAndExpandInvalidation( // nnqqttwwzzccffi|i . // oorruuxxaaddggj|j . // oorruuxxaaddggj|j . - // ---------------+ - - - - - - - -+ <- old pile edge + // ---------------+ - - - - - - - -+ <- min pile edge // . - // - - - - - - - - - - - - - - - -+ <- new pile edge + // - - - - - - - - - - - - - - - -+ <- max pile edge // // If you were to slide a vertical beam from the left edge of the - // old edge rect toward the right, it would either hit the right edge - // of the old edge rect, or the interest rect (expanded to the bounds + // delta edge rect toward the right, it would either hit the right edge + // of the delta edge rect, or the interest rect (expanded to the bounds // of the tiles it touches). The same is true for a beam parallel to - // any of the four edges, sliding accross the old edge rect. We use + // any of the four edges, sliding across the delta edge rect. We use // the union of these four rectangles generated by these beams to - // determine which part of the old edge rect is outside of the expanded + // determine which part of the delta edge rect is outside of the expanded // interest rect. // - // Case 1: Intersect rect is outside the old edge rect. It can be + // Case 1: Intersect rect is outside the delta edge rect. It can be // either on the left or the right. The |left_rect| and |right_rect|, // cover this case, one will be empty and one will cover the full - // old edge rect. In the picture below, |left_rect| would cover the - // old edge rect, and |right_rect| would be empty. + // delta edge rect. In the picture below, |left_rect| would cover the + // delta edge rect, and |right_rect| would be empty. // +----------------------+ |^^^^^^^^^^^^^^^| - // |===> OLD EDGE RECT | | | + // |===> DELTA EDGE RECT | | | // |===> | | INTEREST RECT | // |===> | | | // |===> | | | // +----------------------+ |vvvvvvvvvvvvvvv| // - // Case 2: Interest rect is inside the old edge rect. It will always - // fill the entire old edge rect horizontally since the old edge rect + // Case 2: Interest rect is inside the delta edge rect. It will always + // fill the entire delta edge rect horizontally since the old edge rect // is a single tile wide, and the interest rect has been expanded to the // bounds of the tiles it touches. In this case the |left_rect| and // |right_rect| will be empty, but the case is handled by the |top_rect| @@ -285,19 +296,19 @@ bool PicturePile::UpdateAndExpandInvalidation( // | | // +-----------------+ // | | - // | OLD EDGE RECT | + // | DELTA EDGE RECT | // +-----------------+ // // Lastly, we need to consider tiles inside the expanded interest rect. // For those tiles, we want to invalidate exactly the newly exposed - // pixels. In the picture below the tiles in the old edge rect have been - // resized and the area covered by periods must be invalidated. The + // pixels. In the picture below the tiles in the delta edge rect have + // been resized and the area covered by periods must be invalidated. The // |exposed_rect| will cover exactly that area. - // v-old pile edge + // v-min pile edge // +---------+-------+ // | ........| // | ........| - // | OLD EDGE.RECT..| + // | DELTA EDGE.RECT.| // | ........| // | ........| // | ........| @@ -308,18 +319,18 @@ bool PicturePile::UpdateAndExpandInvalidation( int left = tiling_.TilePositionX(min_toss_x); int right = left + tiling_.TileSizeX(min_toss_x); - int top = old_tiling_rect_over_tiles.y(); - int bottom = old_tiling_rect_over_tiles.bottom(); + int top = min_tiling_rect_over_tiles.y(); + int bottom = min_tiling_rect_over_tiles.bottom(); int left_until = std::min(interest_rect_over_tiles.x(), right); int right_until = std::max(interest_rect_over_tiles.right(), left); int top_until = std::min(interest_rect_over_tiles.y(), bottom); int bottom_until = std::max(interest_rect_over_tiles.bottom(), top); - int exposed_left = old_tiling_size.width(); - int exposed_left_until = tiling_size().width(); + int exposed_left = min_tiling_size.width(); + int exposed_left_until = max_tiling_size.width(); int exposed_top = top; - int exposed_bottom = tiling_size().height(); + int exposed_bottom = max_tiling_size.height(); DCHECK_GE(exposed_left, left); gfx::Rect left_rect(left, top, left_until - left, bottom - top); @@ -339,23 +350,23 @@ bool PicturePile::UpdateAndExpandInvalidation( } if (min_toss_y < tiling_.num_tiles_y()) { // The same thing occurs here as in the case above, but the invalidation - // rect is the bounding box around the bottom row of tiles in the old + // rect is the bounding box around the bottom row of tiles in the min // pile. This would be tiles {o,r,u,x,a,d,g,j} in the above picture. int top = tiling_.TilePositionY(min_toss_y); int bottom = top + tiling_.TileSizeY(min_toss_y); - int left = old_tiling_rect_over_tiles.x(); - int right = old_tiling_rect_over_tiles.right(); + int left = min_tiling_rect_over_tiles.x(); + int right = min_tiling_rect_over_tiles.right(); int top_until = std::min(interest_rect_over_tiles.y(), bottom); int bottom_until = std::max(interest_rect_over_tiles.bottom(), top); int left_until = std::min(interest_rect_over_tiles.x(), right); int right_until = std::max(interest_rect_over_tiles.right(), left); - int exposed_top = old_tiling_size.height(); - int exposed_top_until = tiling_size().height(); + int exposed_top = min_tiling_size.height(); + int exposed_top_until = max_tiling_size.height(); int exposed_left = left; - int exposed_right = tiling_size().width(); + int exposed_right = max_tiling_size.width(); DCHECK_GE(exposed_top, top); gfx::Rect left_rect(left, top, left_until - left, bottom - top); diff --git a/cc/resources/picture_pile_unittest.cc b/cc/resources/picture_pile_unittest.cc index 60a1f0b71a763..00b1b0c97fb6d 100644 --- a/cc/resources/picture_pile_unittest.cc +++ b/cc/resources/picture_pile_unittest.cc @@ -621,7 +621,8 @@ TEST_P(PicturePileResizeCornerTest, ResizePileOutsideInterestRect) { grow_down_tiling_size, CornerSinglePixelRect(corner, grow_down_tiling_size)); - // We should have lost the recordings in the bottom row. + // We should have lost all of the recordings in the bottom row as none of them + // are in the current interest rect (which is either the above or below it). EXPECT_EQ(6, pile_.tiling().num_tiles_x()); EXPECT_EQ(8, pile_.tiling().num_tiles_y()); for (int i = 0; i < 6; ++i) { @@ -650,7 +651,8 @@ TEST_P(PicturePileResizeCornerTest, ResizePileOutsideInterestRect) { base_tiling_size, CornerSinglePixelRect(corner, base_tiling_size)); - // We should have lost the recordings that are now outside the tiling only. + // When shrinking, we should have lost all the recordings in the bottom row + // not touching the interest rect. EXPECT_EQ(6, pile_.tiling().num_tiles_x()); EXPECT_EQ(6, pile_.tiling().num_tiles_y()); for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { @@ -658,12 +660,49 @@ TEST_P(PicturePileResizeCornerTest, ResizePileOutsideInterestRect) { TestPicturePile::PictureMapKey key(i, j); TestPicturePile::PictureMap& map = pile_.picture_map(); TestPicturePile::PictureMap::iterator it = map.find(key); - EXPECT_EQ(j < 6, it != map.end() && it->second.GetPicture()); + bool expect_tile; + switch (corner) { + case TOP_LEFT: + case TOP_RIGHT: + expect_tile = j < 5; + break; + case BOTTOM_LEFT: + // The interest rect in the bottom left tile means we'll record it. + expect_tile = j < 5 || (j == 5 && i == 0); + break; + case BOTTOM_RIGHT: + // The interest rect in the bottom right tile means we'll record it. + expect_tile = j < 5 || (j == 5 && i == 5); + break; + } + EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture()); } } - // No invalidation when shrinking. - expected_invalidation.Clear(); + // When shrinking, the previously exposed region is invalidated. + expected_invalidation = SubtractRegions(gfx::Rect(grow_down_tiling_size), + gfx::Rect(base_tiling_size)); + // The whole bottom row of tiles (except any with the interest rect) are + // dropped. + gfx::Rect bottom_row_minus_existing_corner = gfx::UnionRects( + pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(5, 5)); + switch (corner) { + case TOP_LEFT: + case TOP_RIGHT: + // No tiles are kept in the changed region because it doesn't + // intersect with the interest rect. + break; + case BOTTOM_LEFT: + bottom_row_minus_existing_corner.Subtract( + pile_.tiling().TileBounds(0, 5)); + break; + case BOTTOM_RIGHT: + bottom_row_minus_existing_corner.Subtract( + pile_.tiling().TileBounds(5, 5)); + break; + } + + expected_invalidation.Union(bottom_row_minus_existing_corner); EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); invalidation.Clear(); @@ -673,7 +712,9 @@ TEST_P(PicturePileResizeCornerTest, ResizePileOutsideInterestRect) { grow_right_tiling_size, CornerSinglePixelRect(corner, grow_right_tiling_size)); - // We should have lost the recordings in the right column. + // We should have lost all of the recordings in the right column as none of + // them are in the current interest rect (which is either entirely left or + // right of it). EXPECT_EQ(8, pile_.tiling().num_tiles_x()); EXPECT_EQ(6, pile_.tiling().num_tiles_y()); for (int i = 0; i < 6; ++i) { @@ -702,7 +743,8 @@ TEST_P(PicturePileResizeCornerTest, ResizePileOutsideInterestRect) { base_tiling_size, CornerSinglePixelRect(corner, base_tiling_size)); - // We should have lost the recordings that are now outside the tiling only. + // When shrinking, we should have lost all the recordings in the right column + // not touching the interest rect. EXPECT_EQ(6, pile_.tiling().num_tiles_x()); EXPECT_EQ(6, pile_.tiling().num_tiles_y()); for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { @@ -710,12 +752,48 @@ TEST_P(PicturePileResizeCornerTest, ResizePileOutsideInterestRect) { TestPicturePile::PictureMapKey key(i, j); TestPicturePile::PictureMap& map = pile_.picture_map(); TestPicturePile::PictureMap::iterator it = map.find(key); - EXPECT_EQ(i < 6, it != map.end() && it->second.GetPicture()); + bool expect_tile; + switch (corner) { + case TOP_LEFT: + case BOTTOM_LEFT: + // No tiles are kept in the changed region because it doesn't + // intersect with the interest rect. + expect_tile = i < 5; + break; + case TOP_RIGHT: + // The interest rect in the top right tile means we'll record it. + expect_tile = i < 5 || (j == 0 && i == 5); + break; + case BOTTOM_RIGHT: + // The interest rect in the bottom right tile means we'll record it. + expect_tile = i < 5 || (j == 5 && i == 5); + break; + } + EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture()); } } - // No invalidation when shrinking. - expected_invalidation.Clear(); + // When shrinking, the previously exposed region is invalidated. + expected_invalidation = SubtractRegions(gfx::Rect(grow_right_tiling_size), + gfx::Rect(base_tiling_size)); + // The whole right column of tiles (except for ones with the interest rect) + // are dropped. + gfx::Rect right_column_minus_existing_corner = gfx::UnionRects( + pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 5)); + switch (corner) { + case TOP_LEFT: + case BOTTOM_LEFT: + break; + case TOP_RIGHT: + right_column_minus_existing_corner.Subtract( + pile_.tiling().TileBounds(5, 0)); + break; + case BOTTOM_RIGHT: + right_column_minus_existing_corner.Subtract( + pile_.tiling().TileBounds(5, 5)); + break; + } + expected_invalidation.Union(right_column_minus_existing_corner); EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); invalidation.Clear(); @@ -740,7 +818,7 @@ TEST_P(PicturePileResizeCornerTest, ResizePileOutsideInterestRect) { // We invalidated all new pixels in the recording. expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size), gfx::Rect(base_tiling_size)); - // But the new pixels don't cover the whole right_column. + // But the new pixels don't cover the whole right column or bottom row. Region right_column_and_bottom_row = UnionRegions(gfx::UnionRects(pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 5)), @@ -753,9 +831,11 @@ TEST_P(PicturePileResizeCornerTest, ResizePileOutsideInterestRect) { invalidation.Clear(); UpdateWholePile(); - UpdateAndExpandInvalidation(&invalidation, base_tiling_size, gfx::Rect()); + UpdateAndExpandInvalidation(&invalidation, base_tiling_size, + CornerSinglePixelRect(corner, base_tiling_size)); - // We should have lost the recordings that are now outside the tiling only. + // We should have lost the recordings in the right column and bottom row, + // except where it intersects the interest rect. EXPECT_EQ(6, pile_.tiling().num_tiles_x()); EXPECT_EQ(6, pile_.tiling().num_tiles_y()); for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { @@ -763,12 +843,54 @@ TEST_P(PicturePileResizeCornerTest, ResizePileOutsideInterestRect) { TestPicturePile::PictureMapKey key(i, j); TestPicturePile::PictureMap& map = pile_.picture_map(); TestPicturePile::PictureMap::iterator it = map.find(key); - EXPECT_EQ(i < 6 && j < 6, it != map.end() && it->second.GetPicture()); + bool expect_tile; + switch (corner) { + case TOP_LEFT: + expect_tile = i < 5 && j < 5; + break; + case TOP_RIGHT: + // The interest rect in the top right tile means we'll record it. + expect_tile = (i < 5 && j < 5) || (j == 0 && i == 5); + break; + case BOTTOM_LEFT: + // The interest rect in the bottom left tile means we'll record it. + expect_tile = (i < 5 && j < 5) || (j == 5 && i == 0); + break; + case BOTTOM_RIGHT: + // The interest rect in the bottom right tile means we'll record it. + expect_tile = (i < 5 && j < 5) || (j == 5 && i == 5); + break; + } + EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture()) + << i << "," << j; } } - // No invalidation when shrinking. - expected_invalidation.Clear(); + // We invalidated all previous pixels in the recording. + expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size), + gfx::Rect(base_tiling_size)); + // The whole right column and bottom row of tiles (except for ones with the + // interest rect) are dropped. + Region right_column_and_bottom_row_minus_existing_corner = + right_column_and_bottom_row; + switch (corner) { + case TOP_LEFT: + break; + case BOTTOM_LEFT: + right_column_and_bottom_row_minus_existing_corner.Subtract( + pile_.tiling().TileBounds(0, 5)); + break; + case TOP_RIGHT: + right_column_and_bottom_row_minus_existing_corner.Subtract( + pile_.tiling().TileBounds(5, 0)); + break; + case BOTTOM_RIGHT: + right_column_and_bottom_row_minus_existing_corner.Subtract( + pile_.tiling().TileBounds(5, 5)); + break; + } + expected_invalidation.Union( + right_column_and_bottom_row_minus_existing_corner); EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); invalidation.Clear(); } @@ -808,261 +930,228 @@ TEST_P(PicturePileResizeCornerTest, SmallResizePileOutsideInterestRect) { } } - UpdateAndExpandInvalidation( - &invalidation, - grow_down_tiling_size, - CornerSinglePixelRect(corner, grow_down_tiling_size)); + // In this test (unlike the large resize test), as all growing and shrinking + // happens within tiles, the resulting invalidation is symmetrical, so use + // this enum to repeat the test both ways. + enum ChangeDirection { GROW, SHRINK, LAST_DIRECTION = SHRINK }; - // We should have lost the recordings in the bottom row that do not intersect - // the interest rect. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - EXPECT_EQ(6, pile_.tiling().num_tiles_y()); - for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { - for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { - TestPicturePile::PictureMapKey key(i, j); - TestPicturePile::PictureMap& map = pile_.picture_map(); - TestPicturePile::PictureMap::iterator it = map.find(key); - bool expect_tile; + // Grow downward. + for (int dir = 0; dir <= LAST_DIRECTION; ++dir) { + gfx::Size new_tiling_size = + dir == GROW ? grow_down_tiling_size : base_tiling_size; + UpdateWholePile(); + UpdateAndExpandInvalidation(&invalidation, new_tiling_size, + CornerSinglePixelRect(corner, new_tiling_size)); + + // We should have lost the recordings in the bottom row that do not + // intersect the interest rect. + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + bool expect_tile; + switch (corner) { + case TOP_LEFT: + case TOP_RIGHT: + expect_tile = j < 5; + break; + case BOTTOM_LEFT: + // The interest rect in the bottom left tile means we'll record it. + expect_tile = j < 5 || (j == 5 && i == 0); + break; + case BOTTOM_RIGHT: + // The interest rect in the bottom right tile means we'll record it. + expect_tile = j < 5 || (j == 5 && i == 5); + break; + } + EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture()); + } + } + + // We invalidated the bottom row outside the new interest rect. The tile + // that insects the interest rect in invalidated only on its newly + // exposed or previously exposed pixels. + if (dir == GROW) { + // Only calculate the expected invalidation while growing, as the tile + // bounds post-growing is the newly exposed / previously exposed sizes. + // Post-shrinking, the tile bounds are smaller, so can't be used. switch (corner) { case TOP_LEFT: case TOP_RIGHT: - expect_tile = j < 5; + expected_invalidation = gfx::UnionRects( + pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(5, 5)); break; case BOTTOM_LEFT: - // The interest rect in the bottom left tile means we'll record it. - expect_tile = j < 5 || (j == 5 && i == 0); + expected_invalidation = gfx::UnionRects( + pile_.tiling().TileBounds(1, 5), pile_.tiling().TileBounds(5, 5)); + expected_invalidation.Union(SubtractRects( + pile_.tiling().TileBounds(0, 5), gfx::Rect(base_tiling_size))); break; case BOTTOM_RIGHT: - // The interest rect in the bottom right tile means we'll record it. - expect_tile = j < 5 || (j == 5 && i == 5); + expected_invalidation = gfx::UnionRects( + pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(4, 5)); + expected_invalidation.Union(SubtractRects( + pile_.tiling().TileBounds(5, 5), gfx::Rect(base_tiling_size))); break; } - EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture()); } + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); } - // We invalidated the bottom row outside the new interest rect. The tile that - // insects the interest rect in invalidated only on its new pixels. - switch (corner) { - case TOP_LEFT: - case TOP_RIGHT: - expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(0, 5), - pile_.tiling().TileBounds(5, 5)); - break; - case BOTTOM_LEFT: - expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(1, 5), - pile_.tiling().TileBounds(5, 5)); - expected_invalidation.Union(SubtractRects(pile_.tiling().TileBounds(0, 5), - gfx::Rect(base_tiling_size))); - break; - case BOTTOM_RIGHT: - expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(0, 5), - pile_.tiling().TileBounds(4, 5)); - expected_invalidation.Union(SubtractRects(pile_.tiling().TileBounds(5, 5), - gfx::Rect(base_tiling_size))); - break; - } - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); - - UpdateWholePile(); - UpdateAndExpandInvalidation(&invalidation, - base_tiling_size, - CornerSinglePixelRect(corner, base_tiling_size)); - - // We should have lost nothing. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - EXPECT_EQ(6, pile_.tiling().num_tiles_y()); - for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { - for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { - TestPicturePile::PictureMapKey key(i, j); - TestPicturePile::PictureMap& map = pile_.picture_map(); - TestPicturePile::PictureMap::iterator it = map.find(key); - EXPECT_TRUE(it != map.end() && it->second.GetPicture()); + // Grow right. + for (int dir = 0; dir <= LAST_DIRECTION; ++dir) { + gfx::Size new_tiling_size = + dir == GROW ? grow_right_tiling_size : base_tiling_size; + UpdateWholePile(); + UpdateAndExpandInvalidation(&invalidation, new_tiling_size, + CornerSinglePixelRect(corner, new_tiling_size)); + + // We should have lost the recordings in the right column. + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + bool expect_tile; + switch (corner) { + case TOP_LEFT: + case BOTTOM_LEFT: + expect_tile = i < 5; + break; + case TOP_RIGHT: + // The interest rect in the top right tile means we'll record it. + expect_tile = i < 5 || (j == 0 && i == 5); + break; + case BOTTOM_RIGHT: + // The interest rect in the bottom right tile means we'll record it. + expect_tile = i < 5 || (j == 5 && i == 5); + break; + } + EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture()); + } } - } - - // We invalidated nothing. - expected_invalidation.Clear(); - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); - - UpdateWholePile(); - UpdateAndExpandInvalidation( - &invalidation, - grow_right_tiling_size, - CornerSinglePixelRect(corner, grow_right_tiling_size)); - // We should have lost the recordings in the right column. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - EXPECT_EQ(6, pile_.tiling().num_tiles_y()); - for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { - for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { - TestPicturePile::PictureMapKey key(i, j); - TestPicturePile::PictureMap& map = pile_.picture_map(); - TestPicturePile::PictureMap::iterator it = map.find(key); - bool expect_tile; + // We invalidated the right column outside the new interest rect. The tile + // that insects the interest rect in invalidated only on its new or + // previously exposed pixels. + if (dir == GROW) { + // Calculate the expected invalidation the first time through the loop. switch (corner) { case TOP_LEFT: case BOTTOM_LEFT: - expect_tile = i < 5; + expected_invalidation = gfx::UnionRects( + pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 5)); break; case TOP_RIGHT: - // The interest rect in the top right tile means we'll record it. - expect_tile = i < 5 || (j == 0 && i == 5); + expected_invalidation = gfx::UnionRects( + pile_.tiling().TileBounds(5, 1), pile_.tiling().TileBounds(5, 5)); + expected_invalidation.Union(SubtractRects( + pile_.tiling().TileBounds(5, 0), gfx::Rect(base_tiling_size))); break; case BOTTOM_RIGHT: - // The interest rect in the bottom right tile means we'll record it. - expect_tile = i < 5 || (j == 5 && i == 5); + expected_invalidation = gfx::UnionRects( + pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 4)); + expected_invalidation.Union(SubtractRects( + pile_.tiling().TileBounds(5, 5), gfx::Rect(base_tiling_size))); break; } - EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture()); } + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); } - // We invalidated the right column outside the new interest rect. The tile - // that insects the interest rect in invalidated only on its new pixels. - switch (corner) { - case TOP_LEFT: - case BOTTOM_LEFT: - expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(5, 0), - pile_.tiling().TileBounds(5, 5)); - break; - case TOP_RIGHT: - expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(5, 1), - pile_.tiling().TileBounds(5, 5)); - expected_invalidation.Union(SubtractRects(pile_.tiling().TileBounds(5, 0), - gfx::Rect(base_tiling_size))); - break; - case BOTTOM_RIGHT: - expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(5, 0), - pile_.tiling().TileBounds(5, 4)); - expected_invalidation.Union(SubtractRects(pile_.tiling().TileBounds(5, 5), - gfx::Rect(base_tiling_size))); - break; - } - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); - - UpdateWholePile(); - UpdateAndExpandInvalidation(&invalidation, - base_tiling_size, - CornerSinglePixelRect(corner, base_tiling_size)); - - // We should have lost nothing. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - EXPECT_EQ(6, pile_.tiling().num_tiles_y()); - for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { - for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { - TestPicturePile::PictureMapKey key(i, j); - TestPicturePile::PictureMap& map = pile_.picture_map(); - TestPicturePile::PictureMap::iterator it = map.find(key); - EXPECT_TRUE(it != map.end() && it->second.GetPicture()); + // Grow both. + for (int dir = 0; dir <= LAST_DIRECTION; ++dir) { + gfx::Size new_tiling_size = + dir == GROW ? grow_both_tiling_size : base_tiling_size; + UpdateWholePile(); + UpdateAndExpandInvalidation(&invalidation, new_tiling_size, + CornerSinglePixelRect(corner, new_tiling_size)); + + // We should have lost the recordings in the right column and bottom row. + // The tile that insects the interest rect in invalidated only on its new + // or previously exposed pixels. + EXPECT_EQ(6, pile_.tiling().num_tiles_x()); + EXPECT_EQ(6, pile_.tiling().num_tiles_y()); + for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { + TestPicturePile::PictureMapKey key(i, j); + TestPicturePile::PictureMap& map = pile_.picture_map(); + TestPicturePile::PictureMap::iterator it = map.find(key); + bool expect_tile; + switch (corner) { + case TOP_LEFT: + expect_tile = i < 5 && j < 5; + break; + case TOP_RIGHT: + // The interest rect in the top right tile means we'll record it. + expect_tile = (i < 5 && j < 5) || (j == 0 && i == 5); + break; + case BOTTOM_LEFT: + // The interest rect in the bottom left tile means we'll record it. + expect_tile = (i < 5 && j < 5) || (j == 5 && i == 0); + break; + case BOTTOM_RIGHT: + // The interest rect in the bottom right tile means we'll record it. + expect_tile = (i < 5 && j < 5) || (j == 5 && i == 5); + break; + } + EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture()) + << i << "," << j; + } } - } - // We invalidated nothing. - expected_invalidation.Clear(); - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); - - UpdateWholePile(); - UpdateAndExpandInvalidation( - &invalidation, - grow_both_tiling_size, - CornerSinglePixelRect(corner, grow_both_tiling_size)); - - // We should have lost the recordings in the right column and bottom row. The - // tile that insects the interest rect in invalidated only on its new pixels. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - EXPECT_EQ(6, pile_.tiling().num_tiles_y()); - for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { - for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { - TestPicturePile::PictureMapKey key(i, j); - TestPicturePile::PictureMap& map = pile_.picture_map(); - TestPicturePile::PictureMap::iterator it = map.find(key); - bool expect_tile; + // We invalidated the right column and the bottom row outside the new + // interest rect. The tile that insects the interest rect in invalidated + // only on its new or previous exposed pixels. + if (dir == GROW) { + // Calculate the expected invalidation the first time through the loop. switch (corner) { case TOP_LEFT: - expect_tile = i < 5 && j < 5; + expected_invalidation = gfx::UnionRects( + pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 5)); + expected_invalidation.Union( + gfx::UnionRects(pile_.tiling().TileBounds(0, 5), + pile_.tiling().TileBounds(5, 5))); break; case TOP_RIGHT: - // The interest rect in the top right tile means we'll record it. - expect_tile = (i < 5 && j < 5) || (j == 0 && i == 5); + expected_invalidation = gfx::UnionRects( + pile_.tiling().TileBounds(5, 1), pile_.tiling().TileBounds(5, 5)); + expected_invalidation.Union( + gfx::UnionRects(pile_.tiling().TileBounds(0, 5), + pile_.tiling().TileBounds(5, 5))); + expected_invalidation.Union(SubtractRects( + pile_.tiling().TileBounds(5, 0), gfx::Rect(base_tiling_size))); break; case BOTTOM_LEFT: - // The interest rect in the bottom left tile means we'll record it. - expect_tile = (i < 5 && j < 5) || (j == 5 && i == 0); + expected_invalidation = gfx::UnionRects( + pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 5)); + expected_invalidation.Union( + gfx::UnionRects(pile_.tiling().TileBounds(1, 5), + pile_.tiling().TileBounds(5, 5))); + expected_invalidation.Union(SubtractRects( + pile_.tiling().TileBounds(0, 5), gfx::Rect(base_tiling_size))); break; case BOTTOM_RIGHT: - // The interest rect in the bottom right tile means we'll record it. - expect_tile = (i < 5 && j < 5) || (j == 5 && i == 5); + expected_invalidation = gfx::UnionRects( + pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 4)); + expected_invalidation.Union( + gfx::UnionRects(pile_.tiling().TileBounds(0, 5), + pile_.tiling().TileBounds(4, 5))); + expected_invalidation.Union(SubtractRegions( + pile_.tiling().TileBounds(5, 5), gfx::Rect(base_tiling_size))); break; } - EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture()) - << i << "," << j; - } - } - - // We invalidated the right column and the bottom row outside the new interest - // rect. The tile that insects the interest rect in invalidated only on its - // new pixels. - switch (corner) { - case TOP_LEFT: - expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(5, 0), - pile_.tiling().TileBounds(5, 5)); - expected_invalidation.Union(gfx::UnionRects( - pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(5, 5))); - break; - case TOP_RIGHT: - expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(5, 1), - pile_.tiling().TileBounds(5, 5)); - expected_invalidation.Union(gfx::UnionRects( - pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(5, 5))); - expected_invalidation.Union(SubtractRects(pile_.tiling().TileBounds(5, 0), - gfx::Rect(base_tiling_size))); - break; - case BOTTOM_LEFT: - expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(5, 0), - pile_.tiling().TileBounds(5, 5)); - expected_invalidation.Union(gfx::UnionRects( - pile_.tiling().TileBounds(1, 5), pile_.tiling().TileBounds(5, 5))); - expected_invalidation.Union(SubtractRects(pile_.tiling().TileBounds(0, 5), - gfx::Rect(base_tiling_size))); - break; - case BOTTOM_RIGHT: - expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(5, 0), - pile_.tiling().TileBounds(5, 4)); - expected_invalidation.Union(gfx::UnionRects( - pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(4, 5))); - expected_invalidation.Union(SubtractRegions( - pile_.tiling().TileBounds(5, 5), gfx::Rect(base_tiling_size))); - break; - } - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); - - UpdateWholePile(); - UpdateAndExpandInvalidation(&invalidation, - base_tiling_size, - CornerSinglePixelRect(corner, base_tiling_size)); - - // We should have lost nothing. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - EXPECT_EQ(6, pile_.tiling().num_tiles_y()); - for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) { - for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) { - TestPicturePile::PictureMapKey key(i, j); - TestPicturePile::PictureMap& map = pile_.picture_map(); - TestPicturePile::PictureMap::iterator it = map.find(key); - EXPECT_TRUE(it != map.end() && it->second.GetPicture()); } + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); + invalidation.Clear(); } - - // We invalidated nothing. - expected_invalidation.Clear(); - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); } INSTANTIATE_TEST_CASE_P( @@ -1139,8 +1228,11 @@ TEST_F(PicturePileTest, ResizePileInsideInterestRect) { } } - // No invalidation when shrinking. - EXPECT_EQ(Region().ToString(), invalidation.ToString()); + // We invalidated the previously exposed pixels on the bottom row of tiles. + expected_invalidation = SubtractRegions(gfx::Rect(grow_down_tiling_size), + gfx::Rect(base_tiling_size)); + EXPECT_TRUE(expected_invalidation.Contains(bottom_row_new_pixels)); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); invalidation.Clear(); UpdateWholePile(); @@ -1185,8 +1277,11 @@ TEST_F(PicturePileTest, ResizePileInsideInterestRect) { } } - // No invalidation when shrinking. - EXPECT_EQ(Region().ToString(), invalidation.ToString()); + // We invalidated the previously exposed pixels on the right column of tiles. + expected_invalidation = SubtractRegions(gfx::Rect(grow_right_tiling_size), + gfx::Rect(base_tiling_size)); + EXPECT_TRUE(expected_invalidation.Contains(right_column_new_pixels)); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); invalidation.Clear(); UpdateWholePile(); @@ -1235,8 +1330,13 @@ TEST_F(PicturePileTest, ResizePileInsideInterestRect) { } } - // No invalidation when shrinking. - EXPECT_EQ(Region().ToString(), invalidation.ToString()); + // We invalidated the previously exposed pixels on the bottom row and right + // column of tiles. + expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size), + gfx::Rect(base_tiling_size)); + EXPECT_TRUE( + expected_invalidation.Contains(bottom_row_and_right_column_new_pixels)); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); invalidation.Clear(); } @@ -1304,8 +1404,10 @@ TEST_F(PicturePileTest, SmallResizePileInsideInterestRect) { } } - // No invalidation when shrinking. - EXPECT_EQ(Region().ToString(), invalidation.ToString()); + // We invalidated the previously exposed pixels. + expected_invalidation = SubtractRegions(gfx::Rect(grow_down_tiling_size), + gfx::Rect(base_tiling_size)); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); invalidation.Clear(); UpdateWholePile(); @@ -1345,8 +1447,10 @@ TEST_F(PicturePileTest, SmallResizePileInsideInterestRect) { } } - // No invalidation when shrinking. - EXPECT_EQ(Region().ToString(), invalidation.ToString()); + // We invalidated the previously exposed pixels. + expected_invalidation = SubtractRegions(gfx::Rect(grow_right_tiling_size), + gfx::Rect(base_tiling_size)); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); invalidation.Clear(); UpdateWholePile(); @@ -1386,8 +1490,10 @@ TEST_F(PicturePileTest, SmallResizePileInsideInterestRect) { } } - // No invalidation when shrinking. - EXPECT_EQ(Region().ToString(), invalidation.ToString()); + // We invalidated the previously exposed pixels. + expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size), + gfx::Rect(base_tiling_size)); + EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); invalidation.Clear(); } diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 00be57f29e124..9bee07e1118b0 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc @@ -2653,7 +2653,18 @@ InputHandlerScrollResult LayerTreeHostImpl::ScrollBy( bool consume_by_top_controls = ShouldTopControlsConsumeScroll(scroll_delta); - for (LayerImpl* layer_impl = CurrentlyScrollingLayer(); + // There's an edge case where the outer viewport isn't scrollable when the + // scroll starts, however, as the top controls show the outer viewport becomes + // scrollable. Therefore, always try scrolling the outer viewport before the + // inner. + // TODO(bokan): Move the top controls logic out of the loop since the scroll + // that causes the outer viewport to become scrollable will still be applied + // to the inner viewport. + LayerImpl* start_layer = CurrentlyScrollingLayer(); + if (start_layer == InnerViewportScrollLayer() && OuterViewportScrollLayer()) + start_layer = OuterViewportScrollLayer(); + + for (LayerImpl* layer_impl = start_layer; layer_impl; layer_impl = layer_impl->parent()) { if (!layer_impl->scrollable()) @@ -2708,40 +2719,49 @@ InputHandlerScrollResult LayerTreeHostImpl::ScrollBy( } } + // Scrolls should bubble perfectly between the outer and inner viewports. + bool allow_unrestricted_bubbling_for_current_layer = + layer_impl == OuterViewportScrollLayer(); + bool allow_bubbling_for_current_layer = + allow_unrestricted_bubbling_for_current_layer || should_bubble_scrolls_; + // If the layer wasn't able to move, try the next one in the hierarchy. bool did_move_layer_x = std::abs(applied_delta.x()) > kEpsilon; bool did_move_layer_y = std::abs(applied_delta.y()) > kEpsilon; did_scroll_x |= did_move_layer_x; did_scroll_y |= did_move_layer_y; if (!did_move_layer_x && !did_move_layer_y) { - // Scrolls should always bubble between the outer and inner viewports - if (should_bubble_scrolls_ || !did_lock_scrolling_layer_ || - layer_impl == OuterViewportScrollLayer()) + if (allow_bubbling_for_current_layer || !did_lock_scrolling_layer_) continue; else break; } did_lock_scrolling_layer_ = true; - if (!should_bubble_scrolls_) { + if (!allow_bubbling_for_current_layer) { active_tree_->SetCurrentlyScrollingLayer(layer_impl); break; } - // If the applied delta is within 45 degrees of the input delta, bail out to - // make it easier to scroll just one layer in one direction without - // affecting any of its parents. - float angle_threshold = 45; - if (MathUtil::SmallestAngleBetweenVectors( - applied_delta, pending_delta) < angle_threshold) { - pending_delta = gfx::Vector2dF(); - break; - } + if (allow_unrestricted_bubbling_for_current_layer) { + pending_delta -= applied_delta; + } else { + // If the applied delta is within 45 degrees of the input delta, bail out + // to make it easier to scroll just one layer in one direction without + // affecting any of its parents. + float angle_threshold = 45; + if (MathUtil::SmallestAngleBetweenVectors(applied_delta, pending_delta) < + angle_threshold) { + pending_delta = gfx::Vector2dF(); + break; + } - // Allow further movement only on an axis perpendicular to the direction in - // which the layer moved. - gfx::Vector2dF perpendicular_axis(-applied_delta.y(), applied_delta.x()); - pending_delta = MathUtil::ProjectVector(pending_delta, perpendicular_axis); + // Allow further movement only on an axis perpendicular to the direction + // in which the layer moved. + gfx::Vector2dF perpendicular_axis(-applied_delta.y(), applied_delta.x()); + pending_delta = + MathUtil::ProjectVector(pending_delta, perpendicular_axis); + } if (gfx::ToRoundedVector2d(pending_delta).IsZero()) break; diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 45d636a547e8a..adc11d0cdc791 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc @@ -2328,6 +2328,8 @@ class LayerTreeHostImplTopControlsTest : public LayerTreeHostImplTest { const gfx::Size& outer_viewport_size, const gfx::Size& scroll_layer_size) { CreateHostImpl(settings_, CreateOutputSurface()); + host_impl_->SetTopControlsLayoutHeight( + settings_.top_controls_height); scoped_ptr root = LayerImpl::Create(host_impl_->active_tree(), 1); @@ -2373,8 +2375,6 @@ class LayerTreeHostImplTopControlsTest : public LayerTreeHostImplTest { outer_viewport_scroll_layer_id); host_impl_->SetViewportSize(inner_viewport_size); - host_impl_->SetTopControlsLayoutHeight( - settings_.top_controls_height); LayerImpl* root_clip_ptr = host_impl_->active_tree()->root_layer(); EXPECT_EQ(inner_viewport_size, root_clip_ptr->bounds()); } @@ -2411,6 +2411,81 @@ TEST_F(LayerTreeHostImplTopControlsTest, ScrollTopControlsByFractionalAmount) { inner_viewport_scroll_layer->FixedContainerSizeDelta()); } +// In this test, the outer viewport is initially unscrollable. We test that a +// scroll initiated on the inner viewport, causing the top controls to show and +// thus making the outer viewport scrollable, still scrolls the outer viewport. +TEST_F(LayerTreeHostImplTopControlsTest, + TopControlsOuterViewportBecomesScrollable) { + SetupTopControlsAndScrollLayerWithVirtualViewport( + gfx::Size(10, 50), gfx::Size(10, 50), gfx::Size(10, 100)); + DrawFrame(); + + LayerImpl *inner_scroll = + host_impl_->active_tree()->InnerViewportScrollLayer(); + LayerImpl *inner_container = + host_impl_->active_tree()->InnerViewportContainerLayer(); + LayerImpl *outer_scroll = + host_impl_->active_tree()->OuterViewportScrollLayer(); + LayerImpl *outer_container = + host_impl_->active_tree()->OuterViewportContainerLayer(); + + // Need SetDrawsContent so ScrollBegin's hit test finds an actual layer. + outer_scroll->SetDrawsContent(true); + host_impl_->active_tree()->SetPageScaleFactorAndLimits(2.f, 1.f, 2.f); + + EXPECT_EQ(InputHandler::ScrollStarted, + host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture)); + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0.f, 50.f)); + + // The entire scroll delta should have been used to hide the top controls. + // The viewport layers should be resized back to their full sizes. + EXPECT_EQ(0.f, + host_impl_->active_tree()->total_top_controls_content_offset()); + EXPECT_EQ(0.f, inner_scroll->TotalScrollOffset().y()); + EXPECT_EQ(100.f, inner_container->BoundsForScrolling().height()); + EXPECT_EQ(100.f, outer_container->BoundsForScrolling().height()); + + // The inner viewport should be scrollable by 50px * page_scale. + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0.f, 100.f)); + EXPECT_EQ(50.f, inner_scroll->TotalScrollOffset().y()); + EXPECT_EQ(0.f, outer_scroll->TotalScrollOffset().y()); + EXPECT_EQ(gfx::ScrollOffset(), outer_scroll->MaxScrollOffset()); + + host_impl_->ScrollEnd(); + + EXPECT_EQ(InputHandler::ScrollStarted, + host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture)); + EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), inner_scroll); + + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0.f, -50.f)); + + // The entire scroll delta should have been used to show the top controls. + // The outer viewport should be resized to accomodate and scrolled to the + // bottom of the document to keep the viewport in place. + EXPECT_EQ(50.f, + host_impl_->active_tree()->total_top_controls_content_offset()); + EXPECT_EQ(50.f, outer_container->BoundsForScrolling().height()); + EXPECT_EQ(50.f, inner_container->BoundsForScrolling().height()); + EXPECT_EQ(25.f, outer_scroll->TotalScrollOffset().y()); + EXPECT_EQ(25.f, inner_scroll->TotalScrollOffset().y()); + + // Now when we continue scrolling, make sure the outer viewport gets scrolled + // since it wasn't scrollable when the scroll began. + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0.f, -20.f)); + EXPECT_EQ(15.f, outer_scroll->TotalScrollOffset().y()); + EXPECT_EQ(25.f, inner_scroll->TotalScrollOffset().y()); + + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0.f, -30.f)); + EXPECT_EQ(0.f, outer_scroll->TotalScrollOffset().y()); + EXPECT_EQ(25.f, inner_scroll->TotalScrollOffset().y()); + + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0.f, -50.f)); + host_impl_->ScrollEnd(); + + EXPECT_EQ(0.f, outer_scroll->TotalScrollOffset().y()); + EXPECT_EQ(0.f, inner_scroll->TotalScrollOffset().y()); +} + // Test that the fixed position container delta is appropriately adjusted // by the top controls showing/hiding and page scale doesn't affect it. TEST_F(LayerTreeHostImplTopControlsTest, FixedContainerDelta) { @@ -7412,6 +7487,49 @@ TEST_F(LayerTreeHostImplVirtualViewportTest, FlingScrollBubblesToInner) { } } +TEST_F(LayerTreeHostImplVirtualViewportTest, + DiagonalScrollBubblesPerfectlyToInner) { + gfx::Size content_size = gfx::Size(100, 160); + gfx::Size outer_viewport = gfx::Size(50, 80); + gfx::Size inner_viewport = gfx::Size(25, 40); + + SetupVirtualViewportLayers(content_size, outer_viewport, inner_viewport); + + LayerImpl* outer_scroll = host_impl_->OuterViewportScrollLayer(); + LayerImpl* inner_scroll = host_impl_->InnerViewportScrollLayer(); + DrawFrame(); + { + gfx::Vector2dF inner_expected; + gfx::Vector2dF outer_expected; + EXPECT_VECTOR_EQ(inner_expected, inner_scroll->TotalScrollOffset()); + EXPECT_VECTOR_EQ(outer_expected, outer_scroll->TotalScrollOffset()); + + // Make sure the scroll goes to the outer viewport first. + EXPECT_EQ(InputHandler::ScrollStarted, + host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture)); + EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->FlingScrollBegin()); + + // Scroll near the edge of the outer viewport. + gfx::Vector2d scroll_delta(inner_viewport.width(), inner_viewport.height()); + host_impl_->ScrollBy(gfx::Point(), scroll_delta); + outer_expected += scroll_delta; + + EXPECT_VECTOR_EQ(inner_expected, inner_scroll->TotalScrollOffset()); + EXPECT_VECTOR_EQ(outer_expected, outer_scroll->TotalScrollOffset()); + + // Now diagonal scroll across the outer viewport boundary in a single event. + // The entirety of the scroll should be consumed, as bubbling between inner + // and outer viewport layers is perfect. + host_impl_->ScrollBy(gfx::Point(), gfx::ScaleVector2d(scroll_delta, 2)); + outer_expected += scroll_delta; + inner_expected += scroll_delta; + host_impl_->ScrollEnd(); + + EXPECT_VECTOR_EQ(inner_expected, inner_scroll->TotalScrollOffset()); + EXPECT_VECTOR_EQ(outer_expected, outer_scroll->TotalScrollOffset()); + } +} + class LayerTreeHostImplWithImplicitLimitsTest : public LayerTreeHostImplTest { public: virtual void SetUp() override { diff --git a/chrome/VERSION b/chrome/VERSION index 67a0cca9480d7..86755127a215a 100644 --- a/chrome/VERSION +++ b/chrome/VERSION @@ -1,4 +1,4 @@ MAJOR=40 MINOR=0 BUILD=2214 -PATCH=0 +PATCH=28 diff --git a/chrome/android/java/res/color/button_tint_menu.xml b/chrome/android/java/res/color/blue_mode_tint.xml similarity index 82% rename from chrome/android/java/res/color/button_tint_menu.xml rename to chrome/android/java/res/color/blue_mode_tint.xml index b8e7fa27bcb88..b918ba4147935 100644 --- a/chrome/android/java/res/color/button_tint_menu.xml +++ b/chrome/android/java/res/color/blue_mode_tint.xml @@ -4,5 +4,5 @@ found in the LICENSE file. --> - + diff --git a/chrome/android/java/res/color/default_button_tint.xml b/chrome/android/java/res/color/dark_mode_tint.xml similarity index 51% rename from chrome/android/java/res/color/default_button_tint.xml rename to chrome/android/java/res/color/dark_mode_tint.xml index c64c121b97243..28f22822e1ecc 100644 --- a/chrome/android/java/res/color/default_button_tint.xml +++ b/chrome/android/java/res/color/dark_mode_tint.xml @@ -4,9 +4,9 @@ found in the LICENSE file. --> - - - + + + - + diff --git a/chrome/android/java/res/color/button_tint_white.xml b/chrome/android/java/res/color/light_mode_tint.xml similarity index 100% rename from chrome/android/java/res/color/button_tint_white.xml rename to chrome/android/java/res/color/light_mode_tint.xml diff --git a/chrome/android/java/res/values-v17/styles.xml b/chrome/android/java/res/values-v17/styles.xml index a30be4a491b70..63a870ff02e98 100644 --- a/chrome/android/java/res/values-v17/styles.xml +++ b/chrome/android/java/res/values-v17/styles.xml @@ -38,6 +38,9 @@ viewStart bold 10dp + + true diff --git a/chrome/app/OWNERS b/chrome/app/OWNERS index 7f71ab861f269..81113aa7db217 100644 --- a/chrome/app/OWNERS +++ b/chrome/app/OWNERS @@ -1,7 +1,7 @@ cpu@chromium.org -per-file address_input_strings.grd*=estade@chromium.org -per-file address_input_strings.grd*=rouslan@chromium.org +per-file address_input_strings*=estade@chromium.org +per-file address_input_strings*=rouslan@chromium.org per-file bookmarks_strings.grdp=* per-file chromeos_strings.grdp=* per-file chromium_strings.grd=* diff --git a/chrome/app/address_input_strings.grd b/chrome/app/address_input_strings.grd index d0f003dce93ea..a349d682bd94a 100644 --- a/chrome/app/address_input_strings.grd +++ b/chrome/app/address_input_strings.grd @@ -130,59 +130,7 @@ third_party/libaddressinput/libaddressinput.gyp. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/chrome/app/address_input_strings_android.grd b/chrome/app/address_input_strings_android.grd new file mode 100644 index 0000000000000..a428258d46482 --- /dev/null +++ b/chrome/app/address_input_strings_android.grd @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/chrome/app/address_input_strings_translations.grdp b/chrome/app/address_input_strings_translations.grdp new file mode 100644 index 0000000000000..50605e6a6be50 --- /dev/null +++ b/chrome/app/address_input_strings_translations.grdp @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index baf3b58d0d882..cd9c710ae1c3d 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -2667,12 +2667,6 @@ Even if you have downloaded files from this website before, the website might ha Server's certificate violates name constraints. - - You attempted to reach <strong>$1paypal.com</strong>, but the server presented a certificate for which the period is too long. - - - The server certificate has a validity period that is too long. - An unknown error has occurred. @@ -6748,7 +6742,14 @@ Keep your key file in a safe place. You will need it to create new versions of y Enables a Smart Lock setting that restricts unlocking to only work when your phone is very close to (roughly, within an arm's length of) the Chrome device. - + + + Enable Link Disambiguation Popup. + + + Enable the zoomed bubble that appears on touchscreens when accidentally touching more than one link at a time. + + @@ -8489,6 +8490,9 @@ Keep your key file in a safe place. You will need it to create new versions of y Quality + + $1200x$2100 dpi + $1300 dpi @@ -10160,7 +10164,7 @@ Chrome ran out of memory. Your $1Chromebook will be unlocked when your Android phone is unlocked and nearby. - Allow unlocking this $1Chromebook only when the phone is within an arm's length away. + Only unlock this $1Chromebook when your phone is within arm’s reach. Turn off @@ -15001,11 +15005,11 @@ Do you accept? Your Android phone must have a lock screen enabled before it can unlock this $1Chromebook. Otherwise, you will need to type in your password. - - Bring your phone closer to your Chromebook to enter. + + Your Android phone is too far away from your $1Chromebook. Bring it closer to enter. - - Your Android phone is too far away. Bring it right next to your $1Chromebook to enter. + + Your Android phone is too far away from your $1Chromebook. Bring it closer to enter. When your phone is unlocked and nearby, you can just click to enter. Otherwise, you'll see a locked icon and need to type your password. diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 0b85a662af228..d2682f5b8ffab 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn @@ -558,6 +558,12 @@ static_library("browser") { if (is_win) { sources += rebase_path(gypi_values.chrome_browser_win_sources, ".", "//chrome") + if (!is_chrome_branded) { + sources -= [ + "google/did_run_updater_win.cc", + "google/did_run_updater_win.h", + ] + } public_deps += [ "//ui/views", "//ui/views/controls/webview", diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 6f7cd2d30ec58..aa32ef7b98eec 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc @@ -1647,6 +1647,13 @@ const Experiment kExperiments[] = { kOsCrOS | kOsWin | kOsLinux, SINGLE_VALUE_TYPE(views::switches::kDisableViewsRectBasedTargeting) }, + { + "enable-link-disambiguation-popup", + IDS_FLAGS_ENABLE_LINK_DISAMBIGUATION_POPUP_NAME, + IDS_FLAGS_ENABLE_LINK_DISAMBIGUATION_POPUP_DESCRIPTION, + kOsCrOS | kOsWin, + SINGLE_VALUE_TYPE(switches::kEnableLinkDisambiguationPopup) + }, #endif #if defined(ENABLE_EXTENSIONS) { diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc index aabbb57be959b..bcfcdec47fd1d 100644 --- a/chrome/browser/android/chrome_jni_registrar.cc +++ b/chrome/browser/android/chrome_jni_registrar.cc @@ -49,6 +49,7 @@ #include "chrome/browser/invalidation/invalidation_service_factory_android.h" #include "chrome/browser/lifetime/application_lifetime_android.h" #include "chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.h" +#include "chrome/browser/notifications/notification_ui_manager_android.h" #include "chrome/browser/prerender/external_prerender_handler_android.h" #include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/search_engines/template_url_service_android.h" @@ -169,6 +170,8 @@ static base::android::RegistrationMethod kChromeRegisteredMethods[] = { { "NavigationPopup", NavigationPopup::RegisterNavigationPopup }, { "NewTabPagePrefs", NewTabPagePrefs::RegisterNewTabPagePrefs }, + { "NotificationUIManager", + NotificationUIManagerAndroid::RegisterNotificationUIManager }, { "OmniboxPrerender", RegisterOmniboxPrerender }, { "OmniboxViewUtil", OmniboxViewUtil::RegisterOmniboxViewUtil }, { "PasswordGenerationPopup", diff --git a/chrome/browser/android/preferences/pref_service_bridge.cc b/chrome/browser/android/preferences/pref_service_bridge.cc index eb8c975213861..c0676403cd90d 100644 --- a/chrome/browser/android/preferences/pref_service_bridge.cc +++ b/chrome/browser/android/preferences/pref_service_bridge.cc @@ -541,6 +541,11 @@ static jstring GetContextualSearchPreference(JNIEnv* env, jobject obj) { Release(); } +static jboolean GetContextualSearchPreferenceIsManaged(JNIEnv* env, + jobject obj) { + return GetPrefService()->IsManagedPreference(prefs::kContextualSearchEnabled); +} + static void SetContextualSearchPreference(JNIEnv* env, jobject obj, jstring pref) { GetPrefService()->SetString(prefs::kContextualSearchEnabled, diff --git a/chrome/browser/android/provider/chrome_browser_provider.cc b/chrome/browser/android/provider/chrome_browser_provider.cc index c3bd2d67533fd..a62de40182c8b 100644 --- a/chrome/browser/android/provider/chrome_browser_provider.cc +++ b/chrome/browser/android/provider/chrome_browser_provider.cc @@ -650,10 +650,12 @@ class AsyncServiceRequest : protected BlockingUIThreadAsyncRequest { // Base class for all asynchronous blocking tasks that use the favicon service. class FaviconServiceTask : public AsyncServiceRequest { public: - FaviconServiceTask(FaviconService* service, - base::CancelableTaskTracker* cancelable_tracker, + FaviconServiceTask(base::CancelableTaskTracker* cancelable_tracker, Profile* profile) - : AsyncServiceRequest(service, cancelable_tracker), + : AsyncServiceRequest( + FaviconServiceFactory::GetForProfile(profile, + Profile::EXPLICIT_ACCESS), + cancelable_tracker), profile_(profile) {} Profile* profile() const { return profile_; } @@ -667,15 +669,18 @@ class FaviconServiceTask : public AsyncServiceRequest { // Retrieves the favicon or touch icon for a URL from the FaviconService. class BookmarkIconFetchTask : public FaviconServiceTask { public: - BookmarkIconFetchTask(FaviconService* favicon_service, - base::CancelableTaskTracker* cancelable_tracker, + BookmarkIconFetchTask(base::CancelableTaskTracker* cancelable_tracker, Profile* profile) - : FaviconServiceTask(favicon_service, cancelable_tracker, profile) {} + : FaviconServiceTask(cancelable_tracker, profile) {} favicon_base::FaviconRawBitmapResult Run(const GURL& url) { float max_scale = ui::GetScaleForScaleFactor( ResourceBundle::GetSharedInstance().GetMaxScaleFactor()); int desired_size_in_pixel = std::ceil(gfx::kFaviconSize * max_scale); + + if (service() == NULL) + return favicon_base::FaviconRawBitmapResult(); + RunAsyncRequestOnUIThreadBlocking( base::Bind(&FaviconService::GetRawFaviconForPageURL, base::Unretained(service()), @@ -1162,8 +1167,6 @@ ChromeBrowserProvider::ChromeBrowserProvider(JNIEnv* env, jobject obj) bookmark_model_ = BookmarkModelFactory::GetForProfile(profile_); top_sites_ = profile_->GetTopSites(); service_.reset(new AndroidHistoryProviderService(profile_)); - favicon_service_.reset(FaviconServiceFactory::GetForProfile(profile_, - Profile::EXPLICIT_ACCESS)); // Registers the notifications we are interested. bookmark_model_->AddObserver(this); @@ -1550,8 +1553,7 @@ ScopedJavaLocalRef ChromeBrowserProvider::GetFaviconOrTouchIcon( return ScopedJavaLocalRef(); GURL url = GURL(ConvertJavaStringToUTF16(env, jurl)); - BookmarkIconFetchTask favicon_task( - favicon_service_.get(), &cancelable_task_tracker_, profile_); + BookmarkIconFetchTask favicon_task(&cancelable_task_tracker_, profile_); favicon_base::FaviconRawBitmapResult bitmap_result = favicon_task.Run(url); if (!bitmap_result.is_valid() || !bitmap_result.bitmap_data.get()) diff --git a/chrome/browser/android/provider/chrome_browser_provider.h b/chrome/browser/android/provider/chrome_browser_provider.h index 13c65a4348d90..f0e9661b9f15b 100644 --- a/chrome/browser/android/provider/chrome_browser_provider.h +++ b/chrome/browser/android/provider/chrome_browser_provider.h @@ -209,7 +209,6 @@ class ChromeBrowserProvider : public BaseBookmarkModelObserver, history::TopSites* top_sites_; scoped_ptr service_; - scoped_ptr favicon_service_; base::CancelableTaskTracker cancelable_task_tracker_; diff --git a/chrome/browser/android/resource_id.h b/chrome/browser/android/resource_id.h index 4af0fbdd121c3..9a1aa9d925660 100644 --- a/chrome/browser/android/resource_id.h +++ b/chrome/browser/android/resource_id.h @@ -17,6 +17,9 @@ DEFINE_RESOURCE_ID(0, 0) DEFINE_RESOURCE_ID(IDR_INFOBAR_AUTOFILL_CC, R.drawable.infobar_autofill_cc) DEFINE_RESOURCE_ID(IDR_INFOBAR_AUTOLOGIN,\ R.drawable.infobar_savepassword_autologin) +// TODO(peter): Include the proper resources for the Notification infobar. +DEFINE_RESOURCE_ID(IDR_INFOBAR_DESKTOP_NOTIFICATIONS,\ + R.drawable.infobar_geolocation) DEFINE_RESOURCE_ID(IDR_INFOBAR_GEOLOCATION, R.drawable.infobar_geolocation) DEFINE_RESOURCE_ID(IDR_INFOBAR_MEDIA_STREAM_CAMERA, R.drawable.infobar_camera) DEFINE_RESOURCE_ID(IDR_INFOBAR_MEDIA_STREAM_MIC, R.drawable.infobar_microphone) diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc index b5dec4f5d4bd8..f49471e61e489 100644 --- a/chrome/browser/android/tab_android.cc +++ b/chrome/browser/android/tab_android.cc @@ -38,6 +38,7 @@ #include "chrome/browser/ui/search/search_tab_helper.h" #include "chrome/browser/ui/tab_contents/core_tab_helper.h" #include "chrome/browser/ui/tab_helpers.h" +#include "chrome/common/instant_types.h" #include "chrome/common/url_constants.h" #include "components/google/core/browser/google_url_tracker.h" #include "components/google/core/browser/google_util.h" @@ -377,18 +378,13 @@ void TabAndroid::Observe(int type, } void TabAndroid::OnFaviconAvailable(const gfx::Image& image) { - ScopedJavaLocalRef bitmap; - SkBitmap favicon = image - .AsImageSkia() - .GetRepresentation( - ResourceBundle::GetSharedInstance().GetMaxScaleFactor()) - .sk_bitmap(); + SkBitmap favicon = image.AsImageSkia().GetRepresentation(1.0f).sk_bitmap(); + if (favicon.empty()) + return; - if (!favicon.empty()) { - bitmap = gfx::ConvertToJavaBitmap(&favicon); - } - JNIEnv* env = base::android::AttachCurrentThread(); - Java_Tab_onFaviconAvailable(env, weak_java_tab_.get(env).obj(), bitmap.obj()); + JNIEnv *env = base::android::AttachCurrentThread(); + Java_Tab_onFaviconAvailable(env, weak_java_tab_.get(env).obj(), + gfx::ConvertToJavaBitmap(&favicon).obj()); } void TabAndroid::Destroy(JNIEnv* env, jobject obj) { @@ -536,7 +532,8 @@ TabAndroid::TabLoadStatus TabAndroid::LoadUrl(JNIEnv* env, chrome::ExtractSearchTermsFromURL(GetProfile(), gurl); if (!search_terms.empty() && prerenderer->CanCommitQuery(web_contents_.get(), search_terms)) { - prerenderer->Commit(search_terms); + EmbeddedSearchRequestParams request_params(gurl); + prerenderer->Commit(search_terms, request_params); if (prerenderer->UsePrerenderedPage(gurl, ¶ms)) return FULL_PRERENDERED_PAGE_LOAD; @@ -602,7 +599,8 @@ TabAndroid::TabLoadStatus TabAndroid::LoadUrl(JNIEnv* env, SearchTabHelper::FromWebContents(web_contents_.get()); if (!search_terms.empty() && search_tab_helper && search_tab_helper->SupportsInstant()) { - search_tab_helper->Submit(search_terms); + EmbeddedSearchRequestParams request_params(gurl); + search_tab_helper->Submit(search_terms, request_params); return DEFAULT_PAGE_LOAD; } load_params.is_renderer_initiated = is_renderer_initiated; diff --git a/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm b/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm index 56db665cb1478..8df88e1b3f7da 100644 --- a/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm +++ b/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm @@ -5,6 +5,7 @@ #import #include +#include "apps/app_lifetime_monitor_factory.h" #include "apps/switches.h" #include "base/auto_reset.h" #include "base/callback.h" @@ -150,6 +151,37 @@ void OnShimQuit(Host* host) override {} DISALLOW_COPY_AND_ASSIGN(WindowedAppShimLaunchObserver); }; +class AppLifetimeMonitorObserver : public apps::AppLifetimeMonitor::Observer { + public: + AppLifetimeMonitorObserver(Profile* profile) + : profile_(profile), activated_count_(0), deactivated_count_(0) { + apps::AppLifetimeMonitorFactory::GetForProfile(profile_)->AddObserver(this); + } + virtual ~AppLifetimeMonitorObserver() { + apps::AppLifetimeMonitorFactory::GetForProfile(profile_) + ->RemoveObserver(this); + } + + int activated_count() { return activated_count_; } + int deactivated_count() { return deactivated_count_; } + + protected: + // AppLifetimeMonitor::Observer overrides: + void OnAppActivated(Profile* profile, const std::string& app_id) override { + ++activated_count_; + } + void OnAppDeactivated(Profile* profile, const std::string& app_id) override { + ++deactivated_count_; + } + + private: + Profile* profile_; + int activated_count_; + int deactivated_count_; + + DISALLOW_COPY_AND_ASSIGN(AppLifetimeMonitorObserver); +}; + NSString* GetBundleID(const base::FilePath& shim_path) { base::FilePath plist_path = shim_path.Append("Contents").Append("Info.plist"); NSMutableDictionary* plist = [NSMutableDictionary @@ -164,6 +196,30 @@ bool HasAppShimHost(Profile* profile, const std::string& app_id) { ->FindHost(profile, app_id); } +base::FilePath GetAppShimPath(Profile* profile, + const extensions::Extension* app) { + // Use a WebAppShortcutCreator to get the path. + web_app::WebAppShortcutCreator shortcut_creator( + web_app::GetWebAppDataDirectory(profile->GetPath(), app->id(), GURL()), + web_app::ShortcutInfoForExtensionAndProfile(app, profile), + extensions::FileHandlersInfo()); + return shortcut_creator.GetInternalShortcutPath(); +} + +void UpdateAppAndAwaitShimCreation(Profile* profile, + const extensions::Extension* app, + const base::FilePath& shim_path) { + // Create the internal app shim by simulating an app update. FilePathWatcher + // is used to wait for file operations on the shim to be finished before + // attempting to launch it. Since all of the file operations are done in the + // same event on the FILE thread, everything will be done by the time the + // watcher's callback is executed. + scoped_refptr file_watcher = + new WindowedFilePathWatcher(shim_path); + web_app::UpdateAllShortcuts(base::string16(), profile, app); + file_watcher->Wait(); +} + } // namespace // Watches for NSNotifications from the shared workspace. @@ -224,9 +280,11 @@ - (void)wait { // Shims require static libraries http://crbug.com/386024. #if defined(COMPONENT_BUILD) #define MAYBE_Launch DISABLED_Launch +#define MAYBE_ShowWindow DISABLED_ShowWindow #define MAYBE_RebuildShim DISABLED_RebuildShim #else #define MAYBE_Launch Launch +#define MAYBE_ShowWindow ShowWindow #define MAYBE_RebuildShim RebuildShim #endif @@ -234,26 +292,12 @@ - (void)wait { // These two cases are combined because the time to run the test is dominated // by loading the extension and creating the shim. IN_PROC_BROWSER_TEST_F(AppShimInteractiveTest, MAYBE_Launch) { - // Install the app. const extensions::Extension* app = InstallPlatformApp("minimal"); - // Use a WebAppShortcutCreator to get the path. - web_app::WebAppShortcutCreator shortcut_creator( - web_app::GetWebAppDataDirectory(profile()->GetPath(), app->id(), GURL()), - web_app::ShortcutInfoForExtensionAndProfile(app, profile()), - extensions::FileHandlersInfo()); - base::FilePath shim_path = shortcut_creator.GetInternalShortcutPath(); + base::FilePath shim_path = GetAppShimPath(profile(), app); EXPECT_FALSE(base::PathExists(shim_path)); - // Create the internal app shim by simulating an app update. FilePathWatcher - // is used to wait for file operations on the shim to be finished before - // attempting to launch it. Since all of the file operations are done in the - // same event on the FILE thread, everything will be done by the time the - // watcher's callback is executed. - scoped_refptr file_watcher = - new WindowedFilePathWatcher(shim_path); - web_app::UpdateAllShortcuts(base::string16(), profile(), app); - file_watcher->Wait(); + UpdateAppAndAwaitShimCreation(profile(), app, shim_path); ASSERT_TRUE(base::PathExists(shim_path)); NSString* bundle_id = GetBundleID(shim_path); @@ -316,6 +360,125 @@ - (void)wait { } } +// Test that the shim's lifetime depends on the visibility of windows. I.e. the +// shim is only active when there are visible windows. +IN_PROC_BROWSER_TEST_F(AppShimInteractiveTest, MAYBE_ShowWindow) { + const extensions::Extension* app = InstallPlatformApp("hidden"); + + base::FilePath shim_path = GetAppShimPath(profile(), app); + EXPECT_FALSE(base::PathExists(shim_path)); + + UpdateAppAndAwaitShimCreation(profile(), app, shim_path); + ASSERT_TRUE(base::PathExists(shim_path)); + NSString* bundle_id = GetBundleID(shim_path); + + // It's impractical to confirm that the shim did not launch by timing out, so + // instead we watch AppLifetimeMonitor::Observer::OnAppActivated. + AppLifetimeMonitorObserver lifetime_observer(profile()); + + // Launch the app. It should create a hidden window, but the shim should not + // launch. + { + ExtensionTestMessageListener launched_listener("Launched", false); + LaunchPlatformApp(app); + EXPECT_TRUE(launched_listener.WaitUntilSatisfied()); + } + extensions::AppWindow* window_1 = GetFirstAppWindow(); + ASSERT_TRUE(window_1); + EXPECT_TRUE(window_1->is_hidden()); + EXPECT_FALSE(HasAppShimHost(profile(), app->id())); + EXPECT_EQ(0, lifetime_observer.activated_count()); + + // Showing the window causes the shim to launch. + { + base::scoped_nsobject ns_observer( + [[WindowedNSNotificationObserver alloc] + initForNotification:NSWorkspaceDidLaunchApplicationNotification + andBundleId:bundle_id]); + WindowedAppShimLaunchObserver observer(app->id()); + window_1->Show(extensions::AppWindow::SHOW_INACTIVE); + [ns_observer wait]; + observer.Wait(); + EXPECT_EQ(1, lifetime_observer.activated_count()); + EXPECT_TRUE(HasAppShimHost(profile(), app->id())); + } + + // Hiding the window causes the shim to quit. + { + base::scoped_nsobject ns_observer( + [[WindowedNSNotificationObserver alloc] + initForNotification:NSWorkspaceDidTerminateApplicationNotification + andBundleId:bundle_id]); + window_1->Hide(); + [ns_observer wait]; + EXPECT_FALSE(HasAppShimHost(profile(), app->id())); + } + + // Launch a second window. It should not launch the shim. + { + ExtensionTestMessageListener launched_listener("Launched", false); + LaunchPlatformApp(app); + EXPECT_TRUE(launched_listener.WaitUntilSatisfied()); + } + const extensions::AppWindowRegistry::AppWindowList& app_windows = + extensions::AppWindowRegistry::Get(profile())->app_windows(); + EXPECT_EQ(2u, app_windows.size()); + extensions::AppWindow* window_2 = app_windows.front(); + EXPECT_NE(window_1, window_2); + ASSERT_TRUE(window_2); + EXPECT_TRUE(window_2->is_hidden()); + EXPECT_FALSE(HasAppShimHost(profile(), app->id())); + EXPECT_EQ(1, lifetime_observer.activated_count()); + + // Showing one of the windows should launch the shim. + { + base::scoped_nsobject ns_observer( + [[WindowedNSNotificationObserver alloc] + initForNotification:NSWorkspaceDidLaunchApplicationNotification + andBundleId:bundle_id]); + WindowedAppShimLaunchObserver observer(app->id()); + window_1->Show(extensions::AppWindow::SHOW_INACTIVE); + [ns_observer wait]; + observer.Wait(); + EXPECT_EQ(2, lifetime_observer.activated_count()); + EXPECT_TRUE(HasAppShimHost(profile(), app->id())); + EXPECT_TRUE(window_2->is_hidden()); + } + + // Showing the other window does nothing. + { + window_2->Show(extensions::AppWindow::SHOW_INACTIVE); + EXPECT_EQ(2, lifetime_observer.activated_count()); + } + + // Showing an already visible window does nothing. + { + window_1->Show(extensions::AppWindow::SHOW_INACTIVE); + EXPECT_EQ(2, lifetime_observer.activated_count()); + } + + // Hiding one window does nothing. + { + AppLifetimeMonitorObserver deactivate_observer(profile()); + window_1->Hide(); + EXPECT_EQ(0, deactivate_observer.deactivated_count()); + } + + // Hiding other window causes the shim to quit. + { + AppLifetimeMonitorObserver deactivate_observer(profile()); + EXPECT_TRUE(HasAppShimHost(profile(), app->id())); + base::scoped_nsobject ns_observer( + [[WindowedNSNotificationObserver alloc] + initForNotification:NSWorkspaceDidTerminateApplicationNotification + andBundleId:bundle_id]); + window_2->Hide(); + [ns_observer wait]; + EXPECT_EQ(1, deactivate_observer.deactivated_count()); + EXPECT_FALSE(HasAppShimHost(profile(), app->id())); + } +} + #if defined(ARCH_CPU_64_BITS) // Tests that a 32 bit shim attempting to launch 64 bit Chrome will eventually diff --git a/chrome/browser/chrome_browser_main_win.cc b/chrome/browser/chrome_browser_main_win.cc index aa39454cb351e..7ab56c5553ac3 100644 --- a/chrome/browser/chrome_browser_main_win.cc +++ b/chrome/browser/chrome_browser_main_win.cc @@ -59,6 +59,10 @@ #include "ui/gfx/switches.h" #include "ui/strings/grit/app_locale_settings.h" +#if defined(GOOGLE_CHROME_BUILD) +#include "chrome/browser/google/did_run_updater_win.h" +#endif + namespace { typedef HRESULT (STDAPICALLTYPE* RegisterApplicationRestartProc)( @@ -262,6 +266,10 @@ void ChromeBrowserMainPartsWin::PostBrowserStart() { // TODO(erikwright): Remove this and the implementation of the experiment by // September 2014. InitializeDisableTerminateOnHeapCorruptionExperiment(); + +#if defined(GOOGLE_CHROME_BUILD) + did_run_updater_.reset(new DidRunUpdater); +#endif } // static diff --git a/chrome/browser/chrome_browser_main_win.h b/chrome/browser/chrome_browser_main_win.h index 573c1e14085e1..3b3ea04db2962 100644 --- a/chrome/browser/chrome_browser_main_win.h +++ b/chrome/browser/chrome_browser_main_win.h @@ -9,6 +9,8 @@ #include "chrome/browser/chrome_browser_main.h" +class DidRunUpdater; + namespace base { class CommandLine; } @@ -63,6 +65,10 @@ class ChromeBrowserMainPartsWin : public ChromeBrowserMainParts { static void SetupInstallerUtilStrings(); private: +#if defined(GOOGLE_CHROME_BUILD) + scoped_ptr did_run_updater_; +#endif + DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainPartsWin); }; diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc index ae22c0cd661af..f08783754538e 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc @@ -23,6 +23,8 @@ #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" #include "chrome/browser/signin/signin_manager_factory.h" #include "chromeos/chromeos_switches.h" +#include "chromeos/network/network_handler.h" +#include "chromeos/network/network_state_handler.h" #include "components/signin/core/browser/profile_oauth2_token_service.h" #include "components/signin/core/browser/signin_manager.h" #include "content/public/browser/browser_thread.h" @@ -811,6 +813,10 @@ bool FileManagerPrivateGetDriveConnectionStateFunction::RunSync() { break; } + result.has_cellular_network_access = + chromeos::NetworkHandler::Get() + ->network_state_handler() + ->FirstNetworkByType(chromeos::NetworkTypePattern::Mobile()); results_ = api::file_manager_private::GetDriveConnectionState::Results:: Create(result); diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc index 21ce2ef9e28b9..984d13189882c 100644 --- a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc +++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc @@ -1097,19 +1097,21 @@ ComponentExtensionIMEManager* scoped_refptr InputMethodManagerImpl::CreateNewState( Profile* profile) { StateImpl* new_state = new StateImpl(this, profile); -#if defined(USE_ATHENA) - // Athena for now doesn't have user preferences for input methods, - // therefore no one sets the active input methods in IMF. So just set - // the default IME here. - // TODO(shuchen): we need to better initialize with user preferences. + + // Active IM should be set to owner's default. + PrefService* prefs = g_browser_process->local_state(); + const std::string initial_input_method_id = + prefs->GetString(chromeos::language_prefs::kPreferredKeyboardLayout); + const InputMethodDescriptor* descriptor = GetInputMethodUtil()->GetInputMethodDescriptorFromId( - GetInputMethodUtil()->GetFallbackInputMethodDescriptor().id()); + initial_input_method_id.empty() + ? GetInputMethodUtil()->GetFallbackInputMethodDescriptor().id() + : initial_input_method_id); if (descriptor) { new_state->active_input_method_ids.push_back(descriptor->id()); new_state->current_input_method = *descriptor; } -#endif return scoped_refptr(new_state); } diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc index 498a0c1ab1d3b..f8e553fef867d 100644 --- a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc +++ b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc @@ -168,6 +168,8 @@ class InputMethodManagerImplTest : public BrowserWithTestWindowTest { mock_delegate_->set_ime_list(ime_list_); scoped_ptr delegate(mock_delegate_); + // CreateNewState(NULL) returns state with non-empty current_input_method. + // So SetState() triggers ChangeInputMethod(). manager_->SetState(manager_->CreateNewState(NULL)); std::vector layouts; @@ -366,12 +368,13 @@ TEST_F(InputMethodManagerImplTest, TestObserver) { manager_->GetActiveIMEState()->EnableLoginLayouts("en-US", keyboard_layouts); EXPECT_EQ(5U, manager_->GetActiveIMEState()->GetActiveInputMethods()->size()); EXPECT_EQ(1, observer.input_method_changed_count_); - EXPECT_EQ(1, observer.input_method_menu_item_changed_count_); + // Menu change is triggered only if current input method was actually changed. + EXPECT_EQ(0, observer.input_method_menu_item_changed_count_); manager_->GetActiveIMEState()->ChangeInputMethod( ImeIdFromEngineId("xkb:us:dvorak:eng"), false /* show_message */); EXPECT_FALSE(observer.last_show_message_); EXPECT_EQ(2, observer.input_method_changed_count_); - EXPECT_EQ(2, observer.input_method_menu_item_changed_count_); + EXPECT_EQ(1, observer.input_method_menu_item_changed_count_); manager_->GetActiveIMEState()->ChangeInputMethod( ImeIdFromEngineId("xkb:us:dvorak:eng"), false /* show_message */); EXPECT_FALSE(observer.last_show_message_); @@ -383,7 +386,7 @@ TEST_F(InputMethodManagerImplTest, TestObserver) { // If the same input method ID is passed, PropertyChanged() is not // notified. - EXPECT_EQ(2, observer.input_method_menu_item_changed_count_); + EXPECT_EQ(1, observer.input_method_menu_item_changed_count_); manager_->RemoveObserver(&observer); menu_manager_->RemoveObserver(&observer); @@ -514,8 +517,8 @@ TEST_F(InputMethodManagerImplTest, TestActiveInputMethods) { TEST_F(InputMethodManagerImplTest, TestEnableTwoLayouts) { // For http://crbug.com/19655#c11 - (8), step 6. TestObserver observer; - manager_->AddObserver(&observer); InitComponentExtension(); + manager_->AddObserver(&observer); manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN); std::vector ids; ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng")); @@ -542,8 +545,8 @@ TEST_F(InputMethodManagerImplTest, TestEnableTwoLayouts) { TEST_F(InputMethodManagerImplTest, TestEnableThreeLayouts) { // For http://crbug.com/19655#c11 - (9). TestObserver observer; - manager_->AddObserver(&observer); InitComponentExtension(); + manager_->AddObserver(&observer); manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN); std::vector ids; ids.push_back(ImeIdFromEngineId("xkb:us::eng")); @@ -575,8 +578,8 @@ TEST_F(InputMethodManagerImplTest, TestEnableThreeLayouts) { TEST_F(InputMethodManagerImplTest, TestEnableLayoutAndIme) { // For http://crbug.com/19655#c11 - (10). TestObserver observer; - manager_->AddObserver(&observer); InitComponentExtension(); + manager_->AddObserver(&observer); manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN); std::vector ids; ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng")); @@ -604,8 +607,8 @@ TEST_F(InputMethodManagerImplTest, TestEnableLayoutAndIme) { TEST_F(InputMethodManagerImplTest, TestEnableLayoutAndIme2) { // For http://crbug.com/19655#c11 - (11). TestObserver observer; - manager_->AddObserver(&observer); InitComponentExtension(); + manager_->AddObserver(&observer); manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN); std::vector ids; ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng")); @@ -628,8 +631,8 @@ TEST_F(InputMethodManagerImplTest, TestEnableLayoutAndIme2) { TEST_F(InputMethodManagerImplTest, TestEnableImes) { TestObserver observer; - manager_->AddObserver(&observer); InitComponentExtension(); + manager_->AddObserver(&observer); manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN); std::vector ids; ids.push_back(ImeIdFromEngineId(kExt2Engine1Id)); @@ -644,8 +647,8 @@ TEST_F(InputMethodManagerImplTest, TestEnableImes) { TEST_F(InputMethodManagerImplTest, TestEnableUnknownIds) { TestObserver observer; - manager_->AddObserver(&observer); InitComponentExtension(); + manager_->AddObserver(&observer); manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN); std::vector ids; ids.push_back("xkb:tl::tlh"); // Klingon, which is not supported. @@ -662,8 +665,8 @@ TEST_F(InputMethodManagerImplTest, TestEnableUnknownIds) { TEST_F(InputMethodManagerImplTest, TestEnableLayoutsThenLock) { // For http://crbug.com/19655#c11 - (14). TestObserver observer; - manager_->AddObserver(&observer); InitComponentExtension(); + manager_->AddObserver(&observer); manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN); std::vector ids; ids.push_back(ImeIdFromEngineId("xkb:us::eng")); @@ -712,8 +715,8 @@ TEST_F(InputMethodManagerImplTest, TestEnableLayoutsThenLock) { TEST_F(InputMethodManagerImplTest, SwitchInputMethodTest) { // For http://crbug.com/19655#c11 - (15). TestObserver observer; - manager_->AddObserver(&observer); InitComponentExtension(); + manager_->AddObserver(&observer); manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN); std::vector ids; ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng")); @@ -764,8 +767,10 @@ TEST_F(InputMethodManagerImplTest, SwitchInputMethodTest) { } TEST_F(InputMethodManagerImplTest, TestXkbSetting) { + EXPECT_EQ(0, keyboard_->set_current_keyboard_layout_by_name_count_); // For http://crbug.com/19655#c11 - (8), step 7-11. InitComponentExtension(); + EXPECT_EQ(1, keyboard_->set_current_keyboard_layout_by_name_count_); manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN); std::vector ids; ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng")); @@ -774,26 +779,26 @@ TEST_F(InputMethodManagerImplTest, TestXkbSetting) { ids.push_back(ImeIdFromEngineId(kNaclMozcUsId)); EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids)); EXPECT_EQ(4U, manager_->GetActiveIMEState()->GetNumActiveInputMethods()); - EXPECT_EQ(1, keyboard_->set_current_keyboard_layout_by_name_count_); + EXPECT_EQ(2, keyboard_->set_current_keyboard_layout_by_name_count_); // See input_methods.txt for an expected XKB layout name. EXPECT_EQ("us(dvorak)", keyboard_->last_layout_); manager_->GetActiveIMEState()->SwitchToNextInputMethod(); - EXPECT_EQ(2, keyboard_->set_current_keyboard_layout_by_name_count_); + EXPECT_EQ(3, keyboard_->set_current_keyboard_layout_by_name_count_); EXPECT_EQ("us(colemak)", keyboard_->last_layout_); manager_->GetActiveIMEState()->SwitchToNextInputMethod(); - EXPECT_EQ(3, keyboard_->set_current_keyboard_layout_by_name_count_); + EXPECT_EQ(4, keyboard_->set_current_keyboard_layout_by_name_count_); EXPECT_EQ("jp", keyboard_->last_layout_); manager_->GetActiveIMEState()->SwitchToNextInputMethod(); - EXPECT_EQ(4, keyboard_->set_current_keyboard_layout_by_name_count_); + EXPECT_EQ(5, keyboard_->set_current_keyboard_layout_by_name_count_); EXPECT_EQ("us", keyboard_->last_layout_); manager_->GetActiveIMEState()->SwitchToNextInputMethod(); - EXPECT_EQ(5, keyboard_->set_current_keyboard_layout_by_name_count_); + EXPECT_EQ(6, keyboard_->set_current_keyboard_layout_by_name_count_); EXPECT_EQ("us(dvorak)", keyboard_->last_layout_); // Disable Dvorak. ids.erase(ids.begin()); EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids)); EXPECT_EQ(3U, manager_->GetActiveIMEState()->GetNumActiveInputMethods()); - EXPECT_EQ(6, keyboard_->set_current_keyboard_layout_by_name_count_); + EXPECT_EQ(7, keyboard_->set_current_keyboard_layout_by_name_count_); EXPECT_EQ("us(colemak)", keyboard_->last_layout_); } @@ -880,8 +885,8 @@ TEST_F(InputMethodManagerImplTest, TestGetCurrentInputMethodPropertiesTwoImes) { TEST_F(InputMethodManagerImplTest, TestNextInputMethod) { TestObserver observer; - manager_->AddObserver(&observer); InitComponentExtension(); + manager_->AddObserver(&observer); std::vector keyboard_layouts; keyboard_layouts.push_back(ImeIdFromEngineId("xkb:us::eng")); // For http://crbug.com/19655#c11 - (1) @@ -921,8 +926,8 @@ TEST_F(InputMethodManagerImplTest, TestNextInputMethod) { TEST_F(InputMethodManagerImplTest, TestPreviousInputMethod) { TestObserver observer; - manager_->AddObserver(&observer); InitComponentExtension(); + manager_->AddObserver(&observer); ui::Accelerator keydown_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN); keydown_accelerator.set_type(ui::ET_KEY_PRESSED); @@ -998,8 +1003,8 @@ TEST_F(InputMethodManagerImplTest, TestPreviousInputMethod) { TEST_F(InputMethodManagerImplTest, TestSwitchToPreviousInputMethodForOneActiveInputMethod) { TestObserver observer; - manager_->AddObserver(&observer); InitComponentExtension(); + manager_->AddObserver(&observer); ui::Accelerator keydown_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN); keydown_accelerator.set_type(ui::ET_KEY_PRESSED); @@ -1024,8 +1029,8 @@ TEST_F(InputMethodManagerImplTest, TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithUsLayouts) { std::string expect_id = ImeIdFromEngineId("xkb:us::eng"); TestObserver observer; - manager_->AddObserver(&observer); InitComponentExtension(); + manager_->AddObserver(&observer); std::vector keyboard_layouts; keyboard_layouts.push_back(ImeIdFromEngineId("xkb:us::eng")); manager_->GetActiveIMEState()->EnableLoginLayouts("en-US", keyboard_layouts); @@ -1169,8 +1174,8 @@ TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithJpIme) { TEST_F(InputMethodManagerImplTest, TestAddRemoveExtensionInputMethods) { TestObserver observer; - manager_->AddObserver(&observer); InitComponentExtension(); + manager_->AddObserver(&observer); manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN); std::vector ids; ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng")); diff --git a/chrome/browser/chromeos/input_method/input_method_util.cc b/chrome/browser/chromeos/input_method/input_method_util.cc index b3dd7f6b1b7fe..a0db58b7ea063 100644 --- a/chrome/browser/chromeos/input_method/input_method_util.cc +++ b/chrome/browser/chromeos/input_method/input_method_util.cc @@ -58,17 +58,19 @@ const size_t kMappingImeIdToMediumLenNameResourceIdLen = // GetFirstLogingInputMethodIds may miss component extension IMEs. To enable // component extension IME as the first loging input method, we have to prepare // component extension IME IDs. +// Note: empty layout means the rule applies for all layouts. const struct { const char* locale; const char* layout; const char* engine_id; } kDefaultInputMethodRecommendation[] = { - { "ja", "us", "nacl_mozc_us" }, { "ja", "jp", "nacl_mozc_jp" }, - { "zh-CN", "us", "zh-t-i0-pinyin" }, - { "zh-TW", "us", "zh-hant-t-i0-und" }, - { "th", "us", "vkd_th" }, - { "vi", "us", "vkd_vi_tcvn" }, + { "ja", "", "nacl_mozc_us" }, + { "zh-CN", "", "zh-t-i0-pinyin" }, + { "zh-TW", "", "zh-hant-t-i0-und" }, + { "th", "", "vkd_th" }, + { "vi", "", "vkd_vi_tcvn" }, + { "ru", "", "xkb:ru::rus" }, }; // The engine ID map for migration. This migration is for input method IDs from @@ -387,8 +389,9 @@ void InputMethodUtil::GetFirstLoginInputMethodIds( = current_input_method.GetPreferredKeyboardLayout(); for (size_t i = 0; i < arraysize(kDefaultInputMethodRecommendation); ++i) { - if (kDefaultInputMethodRecommendation[i].locale == language_code && - kDefaultInputMethodRecommendation[i].layout == current_layout) { + if (kDefaultInputMethodRecommendation[i].locale == language_code && ( + !kDefaultInputMethodRecommendation[i].layout[0] || + kDefaultInputMethodRecommendation[i].layout == current_layout)) { out_input_method_ids->push_back( extension_ime_util::GetInputMethodIDByEngineID( kDefaultInputMethodRecommendation[i].engine_id)); @@ -524,15 +527,17 @@ void InputMethodUtil::UpdateHardwareLayoutCache() { if (IsLoginKeyboard(hardware_layouts_[i])) hardware_login_layouts_.push_back(hardware_layouts_[i]); } - if (hardware_layouts_.empty()) { - // This is totally fine if it's empty. The hardware keyboard layout is - // not stored if startup_manifest.json (OEM customization data) is not - // present (ex. Cr48 doen't have that file). - hardware_layouts_.push_back(GetFallbackInputMethodDescriptor().id()); - } - if (hardware_login_layouts_.empty()) - hardware_login_layouts_.push_back(GetFallbackInputMethodDescriptor().id()); + if (hardware_login_layouts_.empty()) { + // This is totally fine if |hardware_layouts_| is empty. The hardware + // keyboard layout is not stored if startup_manifest.json + // (OEM customization data) is not present (ex. Cr48 doen't have that file). + // So need to make sure |hardware_login_layouts_| is not empty, and + // |hardware_layouts_| contains at least one login layout. + std::string fallback_id = GetFallbackInputMethodDescriptor().id(); + hardware_layouts_.insert(hardware_layouts_.begin(), fallback_id); + hardware_login_layouts_.push_back(fallback_id); + } } void InputMethodUtil::SetHardwareKeyboardLayoutForTesting( diff --git a/chrome/browser/chromeos/input_method/input_method_util_unittest.cc b/chrome/browser/chromeos/input_method/input_method_util_unittest.cc index 97b51b62609f8..9f001b701e0cc 100644 --- a/chrome/browser/chromeos/input_method/input_method_util_unittest.cc +++ b/chrome/browser/chromeos/input_method/input_method_util_unittest.cc @@ -481,5 +481,23 @@ TEST_F(InputMethodUtilTest, TestInputMethodIDMigration) { } } +// Test getting hardware input method IDs. +TEST_F(InputMethodUtilTest, TestHardwareInputMethodIDs) { + util_.SetHardwareKeyboardLayoutForTesting("xkb:ru::rus"); + std::vector input_method_ids = util_.GetHardwareInputMethodIds(); + std::vector login_input_method_ids = + util_.GetHardwareLoginInputMethodIds(); + + EXPECT_EQ(2U, input_method_ids.size()); + EXPECT_EQ(1U, login_input_method_ids.size()); + + EXPECT_EQ("xkb:us::eng", extension_ime_util::GetComponentIDByInputMethodID( + input_method_ids[0])); + EXPECT_EQ("xkb:ru::rus", extension_ime_util::GetComponentIDByInputMethodID( + input_method_ids[1])); + EXPECT_EQ("xkb:us::eng", extension_ime_util::GetComponentIDByInputMethodID( + login_input_method_ids[0])); +} + } // namespace input_method } // namespace chromeos diff --git a/chrome/browser/chromeos/login/oobe_browsertest.cc b/chrome/browser/chromeos/login/oobe_browsertest.cc index c9ae41ce208f3..51a33eccf2641 100644 --- a/chrome/browser/chromeos/login/oobe_browsertest.cc +++ b/chrome/browser/chromeos/login/oobe_browsertest.cc @@ -8,16 +8,12 @@ #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h" #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h" #include "chrome/browser/chromeos/login/ui/webui_login_display.h" -#include "chrome/browser/chromeos/login/ui/webui_login_view.h" #include "chrome/browser/chromeos/login/wizard_controller.h" -#include "chrome/browser/defaults.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h" #include "chrome/common/chrome_switches.h" #include "chrome/test/base/in_process_browser_test.h" #include "chromeos/chromeos_switches.h" -#include "content/public/browser/web_contents.h" -#include "content/public/common/renderer_preferences.h" #include "content/public/test/test_utils.h" #include "google_apis/gaia/fake_gaia.h" #include "google_apis/gaia/gaia_switches.h" @@ -125,30 +121,4 @@ IN_PROC_BROWSER_TEST_F(OobeTest, Accelerator) { OobeScreenWaiter(OobeDisplay::SCREEN_OOBE_ENROLLMENT).Wait(); } -IN_PROC_BROWSER_TEST_F(OobeTest, LinkDisambiguationDefaultRespected) { - chromeos::LoginDisplayHostImpl* display_host = - static_cast( - chromeos::LoginDisplayHostImpl::default_host()); - ASSERT_TRUE(display_host); - chromeos::WebUILoginView* login_view = display_host->GetWebUILoginView(); - ASSERT_TRUE(login_view); - content::WebContents* web_contents = login_view->GetWebContents(); - ASSERT_TRUE(web_contents); - content::RendererPreferences* prefs = web_contents->GetMutableRendererPrefs(); - ASSERT_TRUE(prefs); - // Per crbug/431163 the WiFi selection dropdown doesn't support the link - // disambiguation popup for gesture events, and this feature is disabled - // within ChromeOS. Ensure that the web preferences reflect the default. - if (browser_defaults::kShowLinkDisambiguationPopup) { - EXPECT_EQ( - content::TapMultipleTargetsStrategy:: - TAP_MULTIPLE_TARGETS_STRATEGY_POPUP, - prefs->tap_multiple_targets_strategy); - } else { - EXPECT_EQ( - content::TapMultipleTargetsStrategy::TAP_MULTIPLE_TARGETS_STRATEGY_NONE, - prefs->tap_multiple_targets_strategy); - } -} - } // namespace chromeos diff --git a/chrome/browser/chromeos/login/reset_browsertest.cc b/chrome/browser/chromeos/login/reset_browsertest.cc index 79a8552ea3c19..7c79a9c2fcc50 100644 --- a/chrome/browser/chromeos/login/reset_browsertest.cc +++ b/chrome/browser/chromeos/login/reset_browsertest.cc @@ -312,4 +312,26 @@ IN_PROC_BROWSER_TEST_F(ResetFirstAfterBootTest, ErrorOnRollbackRequested) { OobeScreenWaiter(OobeDisplay::SCREEN_ERROR_MESSAGE).Wait(); } +IN_PROC_BROWSER_TEST_F(ResetFirstAfterBootTest, PRE_RevertAfterCancel) { + PrefService* prefs = g_browser_process->local_state(); + prefs->SetBoolean(prefs::kFactoryResetRequested, true); + RegisterSomeUser(); +} + +IN_PROC_BROWSER_TEST_F(ResetFirstAfterBootTest, RevertAfterCancel) { + update_engine_client_->set_can_rollback_check_result(true); + OobeScreenWaiter(OobeDisplay::SCREEN_OOBE_RESET).Wait(); + EXPECT_EQ(0, power_manager_client_->num_request_restart_calls()); + EXPECT_EQ(0, session_manager_client_->start_device_wipe_call_count()); + EXPECT_EQ(0, update_engine_client_->rollback_call_count()); + JSExpect("!$('reset').classList.contains('rollback-proposal-view')"); + InvokeRollbackOption(); + JSExpect("$('reset').classList.contains('rollback-proposal-view')"); + CloseResetScreen(); + InvokeResetScreen(); + OobeScreenWaiter(OobeDisplay::SCREEN_OOBE_RESET).Wait(); + InvokeRollbackOption(); + JSExpect("$('reset').classList.contains('rollback-proposal-view')"); +} + } // namespace chromeos diff --git a/chrome/browser/chromeos/login/saml/saml_browsertest.cc b/chrome/browser/chromeos/login/saml/saml_browsertest.cc index 15371f2c47208..44e8402274750 100644 --- a/chrome/browser/chromeos/login/saml/saml_browsertest.cc +++ b/chrome/browser/chromeos/login/saml/saml_browsertest.cc @@ -463,8 +463,7 @@ IN_PROC_BROWSER_TEST_F(SamlTest, SamlUI) { } // Tests the sign-in flow when the credentials passing API is used. -// Disabled for flakiness/failing: https://crbug.com/430373 -IN_PROC_BROWSER_TEST_F(SamlTest, DISABLED_CredentialPassingAPI) { +IN_PROC_BROWSER_TEST_F(SamlTest, CredentialPassingAPI) { fake_saml_idp()->SetLoginHTMLTemplate("saml_api_login.html"); fake_saml_idp()->SetLoginAuthHTMLTemplate("saml_api_login_auth.html"); StartSamlAndWaitForIdpPageLoad(kFirstSAMLUserEmail); diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.cc b/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.cc index 514f2f2b6fe88..40fa9842d8394 100644 --- a/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.cc +++ b/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.cc @@ -27,6 +27,8 @@ #include "chrome/browser/supervised_user/supervised_user_sync_service.h" #include "chrome/browser/supervised_user/supervised_user_sync_service_factory.h" #include "chrome/grit/generated_resources.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/session_manager_client.h" #include "chromeos/login/auth/key.h" #include "chromeos/login/auth/user_context.h" #include "chromeos/network/network_state.h" @@ -202,10 +204,16 @@ std::string SupervisedUserCreationScreen::GetName() const { } void SupervisedUserCreationScreen::AbortFlow() { + DBusThreadManager::Get() + ->GetSessionManagerClient() + ->NotifySupervisedUserCreationFinished(); controller_->CancelCreation(); } void SupervisedUserCreationScreen::FinishFlow() { + DBusThreadManager::Get() + ->GetSessionManagerClient() + ->NotifySupervisedUserCreationFinished(); controller_->FinishCreation(); } @@ -358,6 +366,9 @@ void SupervisedUserCreationScreen::OnManagerLoginFailure() { void SupervisedUserCreationScreen::OnManagerFullyAuthenticated( Profile* manager_profile) { + DBusThreadManager::Get() + ->GetSessionManagerClient() + ->NotifySupervisedUserCreationStarted(); manager_signin_in_progress_ = false; DCHECK(controller_.get()); // For manager user, move desktop to locked container so that windows created diff --git a/chrome/browser/chromeos/ownership/owner_settings_service_chromeos.cc b/chrome/browser/chromeos/ownership/owner_settings_service_chromeos.cc index f30a5fa61b485..1912712a441e5 100644 --- a/chrome/browser/chromeos/ownership/owner_settings_service_chromeos.cc +++ b/chrome/browser/chromeos/ownership/owner_settings_service_chromeos.cc @@ -157,7 +157,6 @@ OwnerSettingsServiceChromeOS::OwnerSettingsServiceChromeOS( profile_(profile), waiting_for_profile_creation_(true), waiting_for_tpm_token_(true), - has_pending_changes_(false), weak_factory_(this), store_settings_factory_(this) { if (TPMTokenLoader::IsInitialized()) { @@ -180,8 +179,6 @@ OwnerSettingsServiceChromeOS::OwnerSettingsServiceChromeOS( registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, content::Source(profile_)); - - UpdateFromService(); } OwnerSettingsServiceChromeOS::~OwnerSettingsServiceChromeOS() { @@ -215,15 +212,23 @@ bool OwnerSettingsServiceChromeOS::Set(const std::string& setting, if (!IsOwner() && !IsOwnerInTests(user_id_)) return false; - UpdateDeviceSettings(setting, value, device_settings_); + pending_changes_.add(setting, make_scoped_ptr(value.DeepCopy())); + + em::ChromeDeviceSettingsProto settings; + if (tentative_settings_.get()) { + settings = *tentative_settings_; + } else if (device_settings_service_->status() == + DeviceSettingsService::STORE_SUCCESS && + device_settings_service_->device_settings()) { + settings = *device_settings_service_->device_settings(); + } + UpdateDeviceSettings(setting, value, settings); em::PolicyData policy_data; policy_data.set_username(user_id_); - CHECK(device_settings_.SerializeToString(policy_data.mutable_policy_value())); - FOR_EACH_OBSERVER(OwnerSettingsService::Observer, - observers_, + CHECK(settings.SerializeToString(policy_data.mutable_policy_value())); + FOR_EACH_OBSERVER(OwnerSettingsService::Observer, observers_, OnTentativeChangesInPolicy(policy_data)); - has_pending_changes_ = true; - StoreDeviceSettings(); + StorePendingChanges(); return true; } @@ -236,12 +241,9 @@ bool OwnerSettingsServiceChromeOS::CommitTentativeDeviceSettings( << user_id_; return false; } - CHECK(device_settings_.ParseFromString(policy->policy_value())); - FOR_EACH_OBSERVER(OwnerSettingsService::Observer, - observers_, - OnTentativeChangesInPolicy(*policy)); - has_pending_changes_ = true; - StoreDeviceSettings(); + tentative_settings_.reset(new em::ChromeDeviceSettingsProto); + CHECK(tentative_settings_->ParseFromString(policy->policy_value())); + StorePendingChanges(); return true; } @@ -273,12 +275,12 @@ void OwnerSettingsServiceChromeOS::OwnerKeySet(bool success) { void OwnerSettingsServiceChromeOS::OwnershipStatusChanged() { DCHECK(thread_checker_.CalledOnValidThread()); - StoreDeviceSettings(); + StorePendingChanges(); } void OwnerSettingsServiceChromeOS::DeviceSettingsUpdated() { DCHECK(thread_checker_.CalledOnValidThread()); - StoreDeviceSettings(); + StorePendingChanges(); } void OwnerSettingsServiceChromeOS::OnDeviceSettingsServiceShutdown() { @@ -586,17 +588,32 @@ void OwnerSettingsServiceChromeOS::ReloadKeypairImpl(const base::Callback< callback)); } -void OwnerSettingsServiceChromeOS::StoreDeviceSettings() { - if (!has_pending_changes_ || store_settings_factory_.HasWeakPtrs()) +void OwnerSettingsServiceChromeOS::StorePendingChanges() { + if (!has_pending_changes() || store_settings_factory_.HasWeakPtrs() || + !device_settings_service_) { return; - if (!UpdateFromService()) + } + + em::ChromeDeviceSettingsProto settings; + if (tentative_settings_.get()) { + settings.Swap(tentative_settings_.get()); + tentative_settings_.reset(); + } else if (device_settings_service_->status() == + DeviceSettingsService::STORE_SUCCESS && + device_settings_service_->device_settings()) { + settings = *device_settings_service_->device_settings(); + } else { return; + } + + for (const auto& change : pending_changes_) + UpdateDeviceSettings(change.first, *change.second, settings); + pending_changes_.clear(); + scoped_ptr policy = AssemblePolicy( - user_id_, device_settings_service_->policy_data(), &device_settings_); - has_pending_changes_ = false; + user_id_, device_settings_service_->policy_data(), &settings); bool rv = AssembleAndSignPolicyAsync( - content::BrowserThread::GetBlockingPool(), - policy.Pass(), + content::BrowserThread::GetBlockingPool(), policy.Pass(), base::Bind(&OwnerSettingsServiceChromeOS::OnPolicyAssembledAndSigned, store_settings_factory_.GetWeakPtr())); if (!rv) @@ -621,23 +638,7 @@ void OwnerSettingsServiceChromeOS::OnSignedPolicyStored(bool success) { FOR_EACH_OBSERVER(OwnerSettingsService::Observer, observers_, OnSignedPolicyStored(success)); - StoreDeviceSettings(); - if (!success) - has_pending_changes_ = true; -} - -bool OwnerSettingsServiceChromeOS::UpdateFromService() { - if (!device_settings_service_ || - device_settings_service_->status() != - DeviceSettingsService::STORE_SUCCESS || - !device_settings_service_->device_settings()) { - return false; - } - enterprise_management::ChromeDeviceSettingsProto settings = - *device_settings_service_->device_settings(); - settings.MergeFrom(device_settings_); - device_settings_.Swap(&settings); - return true; + StorePendingChanges(); } } // namespace chromeos diff --git a/chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h b/chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h index 6b24bfed3328b..1e6415f60c18a 100644 --- a/chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h +++ b/chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h @@ -9,7 +9,9 @@ #include #include "base/callback_forward.h" +#include "base/containers/scoped_ptr_hash_map.h" #include "base/macros.h" +#include "base/values.h" #include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h" #include "chrome/browser/chromeos/settings/device_settings_service.h" #include "chromeos/dbus/session_manager_client.h" @@ -83,7 +85,9 @@ class OwnerSettingsServiceChromeOS : public ownership::OwnerSettingsService, const base::Value& value, enterprise_management::ChromeDeviceSettingsProto& settings); - bool has_pending_changes() const { return has_pending_changes_; } + bool has_pending_changes() const { + return !pending_changes_.empty() || tentative_settings_.get(); + } private: friend class OwnerSettingsServiceChromeOSFactory; @@ -104,10 +108,8 @@ class OwnerSettingsServiceChromeOS : public ownership::OwnerSettingsService, // Possibly notifies DeviceSettingsService that owner's keypair is loaded. virtual void OnPostKeypairLoadedActions() override; - // Tries to sign store current device settings if there're pending - // changes in device settings and no active previous call to - // DeviceSettingsService::Store(). - void StoreDeviceSettings(); + // Tries to apply recent changes to device settings proto, sign it and store. + void StorePendingChanges(); // Called when current device settings are successfully signed. // Sends signed settings for storage. @@ -119,10 +121,6 @@ class OwnerSettingsServiceChromeOS : public ownership::OwnerSettingsService, // settings again. void OnSignedPolicyStored(bool success); - // Fetches device settings from DeviceSettingsService and merges - // them with local device settings. - bool UpdateFromService(); - DeviceSettingsService* device_settings_service_; // Profile this service instance belongs to. @@ -137,15 +135,12 @@ class OwnerSettingsServiceChromeOS : public ownership::OwnerSettingsService, // Whether TPM token still needs to be initialized. bool waiting_for_tpm_token_; - // The device settings. This may be different from the actual - // current device settings (which can be obtained from - // DeviceSettingsService) in case the device does not have an owner - // yet or there are pending changes that have not yet been written - // to session_manager. - enterprise_management::ChromeDeviceSettingsProto device_settings_; + // A set of pending changes to device settings. + base::ScopedPtrHashMap pending_changes_; - // True if some settings were changed but not stored. - bool has_pending_changes_; + // A protobuf containing pending changes to device settings. + scoped_ptr + tentative_settings_; content::NotificationRegistrar registrar_; diff --git a/chrome/browser/chromeos/settings/device_settings_test_helper.cc b/chrome/browser/chromeos/settings/device_settings_test_helper.cc index fed7034528326..537c3bf3331a4 100644 --- a/chrome/browser/chromeos/settings/device_settings_test_helper.cc +++ b/chrome/browser/chromeos/settings/device_settings_test_helper.cc @@ -113,6 +113,10 @@ void DeviceSettingsTestHelper::StartSession(const std::string& user_email) {} void DeviceSettingsTestHelper::StopSession() {} +void DeviceSettingsTestHelper::NotifySupervisedUserCreationStarted() {} + +void DeviceSettingsTestHelper::NotifySupervisedUserCreationFinished() {} + void DeviceSettingsTestHelper::StartDeviceWipe() {} void DeviceSettingsTestHelper::RequestLockScreen() {} diff --git a/chrome/browser/chromeos/settings/device_settings_test_helper.h b/chrome/browser/chromeos/settings/device_settings_test_helper.h index 8100563216d35..a3edc72509bc8 100644 --- a/chrome/browser/chromeos/settings/device_settings_test_helper.h +++ b/chrome/browser/chromeos/settings/device_settings_test_helper.h @@ -92,6 +92,8 @@ class DeviceSettingsTestHelper : public SessionManagerClient { virtual void RestartJob(int pid, const std::string& command_line) override; virtual void StartSession(const std::string& user_email) override; virtual void StopSession() override; + virtual void NotifySupervisedUserCreationStarted() override; + virtual void NotifySupervisedUserCreationFinished() override; virtual void StartDeviceWipe() override; virtual void RequestLockScreen() override; virtual void NotifyLockScreenShown() override; diff --git a/chrome/browser/component_updater/recovery_component_installer.cc b/chrome/browser/component_updater/recovery_component_installer.cc index f6b5727a13317..897230ea4e7ea 100644 --- a/chrome/browser/component_updater/recovery_component_installer.cc +++ b/chrome/browser/component_updater/recovery_component_installer.cc @@ -120,6 +120,11 @@ bool RecoveryComponentInstaller::Install(const base::DictionaryValue& manifest, base::FilePath path; if (!PathService::Get(DIR_RECOVERY_BASE, &path)) return false; + if (!base::PathExists(path)) { + if (!base::CreateDirectory(path)) { + return false; + } + } path = path.AppendASCII(version.GetString()); if (base::PathExists(path) && !base::DeleteFile(path, true)) return false; diff --git a/chrome/browser/content_settings/tab_specific_content_settings.cc b/chrome/browser/content_settings/tab_specific_content_settings.cc index c4c7d8a83ef2f..d15e3853fe318 100644 --- a/chrome/browser/content_settings/tab_specific_content_settings.cc +++ b/chrome/browser/content_settings/tab_specific_content_settings.cc @@ -511,7 +511,19 @@ void TabSpecificContentSettings::OnProtectedMediaIdentifierPermissionSet( TabSpecificContentSettings::MicrophoneCameraState TabSpecificContentSettings::GetMicrophoneCameraState() const { - return microphone_camera_state_; + MicrophoneCameraState state = microphone_camera_state_; + + // Include capture devices in the state if there are still consumers of the + // approved media stream. + scoped_refptr media_indicator = + MediaCaptureDevicesDispatcher::GetInstance()-> + GetMediaStreamCaptureIndicator(); + if (media_indicator->IsCapturingAudio(web_contents())) + state |= MICROPHONE_ACCESSED; + if (media_indicator->IsCapturingVideo(web_contents())) + state |= CAMERA_ACCESSED; + + return state; } bool TabSpecificContentSettings::IsMicrophoneCameraStateChanged() const { diff --git a/chrome/browser/content_settings/tab_specific_content_settings.h b/chrome/browser/content_settings/tab_specific_content_settings.h index 063b5253f16ff..707bacfb15ec3 100644 --- a/chrome/browser/content_settings/tab_specific_content_settings.h +++ b/chrome/browser/content_settings/tab_specific_content_settings.h @@ -228,10 +228,12 @@ class TabSpecificContentSettings } // Returns the state of the camera and microphone usage. + // The return value always includes all active media capture devices, on top + // of the devices from the last request. MicrophoneCameraState GetMicrophoneCameraState() const; - // Returns whether the state of the camera and microphone usage or device has - // changed. + // Returns whether the camera or microphone permission or media device setting + // has changed since the last permission request. bool IsMicrophoneCameraStateChanged() const; // Returns the ContentSettingsUsagesState that controls the diff --git a/chrome/browser/defaults.cc b/chrome/browser/defaults.cc index ff39b1d759cdd..6d6b6b6e881df 100644 --- a/chrome/browser/defaults.cc +++ b/chrome/browser/defaults.cc @@ -16,14 +16,6 @@ const bool kCanToggleSystemTitleBar = true; const int kOmniboxFontPixelSize = 16; -#if defined(TOOLKIT_VIEWS) -#if defined(OS_WIN) -const bool kShowLinkDisambiguationPopup = true; -#else -const bool kShowLinkDisambiguationPopup = false; -#endif -#endif - #if defined(OS_CHROMEOS) || defined(OS_MACOSX) const bool kBrowserAliveWithNoWindows = true; const bool kShowExitMenuItem = false; diff --git a/chrome/browser/defaults.h b/chrome/browser/defaults.h index 157d56167c735..41b16d6c8aecf 100644 --- a/chrome/browser/defaults.h +++ b/chrome/browser/defaults.h @@ -33,12 +33,6 @@ const int kMiniTabWidth = 64; const int kMiniTabWidth = 56; #endif -#if defined(TOOLKIT_VIEWS) -// Whether to show a Link Disambiguation Popup Bubble if the browser detects an -// ambiguous touch event. -extern const bool kShowLinkDisambiguationPopup; -#endif - // Can the browser be alive without any browser windows? extern const bool kBrowserAliveWithNoWindows; diff --git a/chrome/browser/devtools/device/usb/android_usb_device.cc b/chrome/browser/devtools/device/usb/android_usb_device.cc index 0820fac3ab6a4..7265654192a48 100644 --- a/chrome/browser/devtools/device/usb/android_usb_device.cc +++ b/chrome/browser/devtools/device/usb/android_usb_device.cc @@ -72,6 +72,7 @@ bool IsAndroidInterface(const UsbInterfaceDescriptor& interface) { scoped_refptr ClaimInterface( crypto::RSAPrivateKey* rsa_key, scoped_refptr usb_handle, + const base::string16& serial, const UsbInterfaceDescriptor& interface) { int inbound_address = 0; int outbound_address = 0; @@ -95,10 +96,6 @@ scoped_refptr ClaimInterface( if (!usb_handle->ClaimInterface(interface.interface_number)) return NULL; - base::string16 serial; - if (!usb_handle->GetDevice()->GetSerialNumber(&serial) || serial.empty()) - return NULL; - return new AndroidUsbDevice(rsa_key, usb_handle, base::UTF16ToASCII(serial), @@ -201,15 +198,19 @@ static void OpenAndroidDeviceOnFileThread( bool success) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); if (success) { - const UsbConfigDescriptor& config = device->GetConfiguration(); - scoped_refptr usb_handle = device->Open(); - if (usb_handle.get()) { - scoped_refptr android_device = - ClaimInterface(rsa_key, usb_handle, config.interfaces[interface_id]); - if (android_device.get()) - devices->push_back(android_device.get()); - else - usb_handle->Close(); + base::string16 serial; + if (device->GetSerialNumber(&serial) && !serial.empty()) { + const UsbConfigDescriptor& config = device->GetConfiguration(); + scoped_refptr usb_handle = device->Open(); + if (usb_handle.get()) { + scoped_refptr android_device = + ClaimInterface(rsa_key, usb_handle, serial, + config.interfaces[interface_id]); + if (android_device.get()) + devices->push_back(android_device.get()); + else + usb_handle->Close(); + } } } barrier.Run(); diff --git a/chrome/browser/extensions/api/copresence/copresence_api_unittest.cc b/chrome/browser/extensions/api/copresence/copresence_api_unittest.cc index 6463c262db4c9..4a7f536b7076e 100644 --- a/chrome/browser/extensions/api/copresence/copresence_api_unittest.cc +++ b/chrome/browser/extensions/api/copresence/copresence_api_unittest.cc @@ -218,6 +218,21 @@ TEST_F(CopresenceApiUnittest, DefaultStrategies) { .token_exchange_strategy().broadcast_scan_configuration()); } +TEST_F(CopresenceApiUnittest, LowPowerStrategy) { + scoped_ptr subscribe_operation(new Operation); + subscribe_operation->subscribe.reset(CreateSubscribe("sub")); + subscribe_operation->subscribe->strategies.reset(new Strategy); + subscribe_operation->subscribe->strategies->low_power.reset(new bool(true)); + + ListValue* operation_list = new ListValue; + operation_list->Append(subscribe_operation->ToValue().release()); + EXPECT_TRUE(ExecuteOperations(operation_list)); + + EXPECT_EQ(copresence::BROADCAST_SCAN_CONFIGURATION_UNKNOWN, + request_sent().manage_subscriptions_request().subscription(0) + .token_exchange_strategy().broadcast_scan_configuration()); +} + TEST_F(CopresenceApiUnittest, UnPubSub) { // First we need to create a publish and a subscribe to cancel. scoped_ptr publish_operation(new Operation); diff --git a/chrome/browser/extensions/api/copresence/copresence_translations.cc b/chrome/browser/extensions/api/copresence/copresence_translations.cc index 57395d403afbb..d00df3fe54b4b 100644 --- a/chrome/browser/extensions/api/copresence/copresence_translations.cc +++ b/chrome/browser/extensions/api/copresence/copresence_translations.cc @@ -34,9 +34,6 @@ int SanitizeTtl(int* user_ttl) { } BroadcastScanConfiguration TranslateStrategy(const Strategy& strategy) { - if (strategy.low_power && *strategy.low_power) - return BROADCAST_SCAN_CONFIGURATION_UNKNOWN; - bool only_broadcast = strategy.only_broadcast && *strategy.only_broadcast; bool only_scan = strategy.only_scan && *strategy.only_scan; @@ -55,10 +52,16 @@ void SetTokenExchangeStrategy(const Strategy* strategy, BroadcastScanConfiguration default_config, TokenExchangeStrategy* strategy_proto) { if (strategy) { - BroadcastScanConfiguration config = TranslateStrategy(*strategy); - strategy_proto->set_broadcast_scan_configuration( - config == BROADCAST_SCAN_CONFIGURATION_UNKNOWN ? - default_config : config); + BroadcastScanConfiguration config; + if (strategy->low_power && *(strategy->low_power)) { + config = BROADCAST_SCAN_CONFIGURATION_UNKNOWN; + } else { + config = TranslateStrategy(*strategy); + if (config == BROADCAST_SCAN_CONFIGURATION_UNKNOWN) + config = default_config; + } + + strategy_proto->set_broadcast_scan_configuration(config); strategy_proto->set_audio_configuration( strategy->audible && *strategy->audible ? AUDIO_CONFIGURATION_AUDIBLE : AUDIO_CONFIGURATION_UNKNOWN); diff --git a/chrome/browser/extensions/api/identity/identity_api.cc b/chrome/browser/extensions/api/identity/identity_api.cc index e5d434d6545da..b00c414d6dad4 100644 --- a/chrome/browser/extensions/api/identity/identity_api.cc +++ b/chrome/browser/extensions/api/identity/identity_api.cc @@ -20,6 +20,7 @@ #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/signin/chrome_signin_client_factory.h" #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" #include "chrome/browser/signin/signin_manager_factory.h" #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h" @@ -785,6 +786,10 @@ void IdentityGetAuthTokenFunction::ShowOAuthApprovalDialog( } OAuth2MintTokenFlow* IdentityGetAuthTokenFunction::CreateMintTokenFlow() { + SigninClient* signin_client = + ChromeSigninClientFactory::GetForProfile(GetProfile()); + std::string signin_scoped_device_id = + signin_client->GetSigninScopedDeviceId(); OAuth2MintTokenFlow* mint_token_flow = new OAuth2MintTokenFlow( this, OAuth2MintTokenFlow::Parameters( @@ -792,6 +797,7 @@ OAuth2MintTokenFlow* IdentityGetAuthTokenFunction::CreateMintTokenFlow() { oauth2_client_id_, std::vector(token_key_->scopes.begin(), token_key_->scopes.end()), + signin_scoped_device_id, gaia_mint_token_mode_)); return mint_token_flow; } diff --git a/chrome/browser/extensions/updater/extension_updater_unittest.cc b/chrome/browser/extensions/updater/extension_updater_unittest.cc index 0d9b6d4783720..4fe395349474d 100644 --- a/chrome/browser/extensions/updater/extension_updater_unittest.cc +++ b/chrome/browser/extensions/updater/extension_updater_unittest.cc @@ -1687,39 +1687,49 @@ class ExtensionUpdaterTest : public testing::Test { // The urls could have been fetched in either order, so use the host to // tell them apart and note the query each used. + GURL url1_fetch_url; + GURL url2_fetch_url; std::string url1_query; std::string url2_query; if (fetched_urls[0].host() == url1.host()) { + url1_fetch_url = fetched_urls[0]; + url2_fetch_url = fetched_urls[1]; + url1_query = fetched_urls[0].query(); url2_query = fetched_urls[1].query(); } else if (fetched_urls[0].host() == url2.host()) { + url1_fetch_url = fetched_urls[1]; + url2_fetch_url = fetched_urls[0]; url1_query = fetched_urls[1].query(); url2_query = fetched_urls[0].query(); } else { NOTREACHED(); } + std::map url1_ping_data = + GetPingDataFromURL(url1_fetch_url); + ParamsMap url1_params = ParamsMap(); + if (!url1_ping_data.empty() && ContainsKey(url1_ping_data, id)) + url1_params = url1_ping_data[id]; + // First make sure the non-google query had no ping parameter. - std::string search_string = "ping%3D"; - EXPECT_TRUE(url2_query.find(search_string) == std::string::npos); + EXPECT_TRUE(GetPingDataFromURL(url2_fetch_url).empty()); // Now make sure the google query had the correct ping parameter. - bool ping_expected = false; bool did_rollcall = false; if (rollcall_ping_days != 0) { - search_string += "r%253D" + base::IntToString(rollcall_ping_days); + ASSERT_TRUE(ContainsKey(url1_params, "r")); + ASSERT_EQ(1u, url1_params["r"].size()); + EXPECT_EQ(base::IntToString(rollcall_ping_days), + *url1_params["r"].begin()); did_rollcall = true; - ping_expected = true; } - if (active_bit && active_ping_days != 0) { - if (did_rollcall) - search_string += "%2526"; - search_string += "a%253D" + base::IntToString(active_ping_days); - ping_expected = true; + if (active_bit && active_ping_days != 0 && did_rollcall) { + ASSERT_TRUE(ContainsKey(url1_params, "a")); + ASSERT_EQ(1u, url1_params["a"].size()); + EXPECT_EQ(base::IntToString(active_ping_days), + *url1_params["a"].begin()); } - bool ping_found = url1_query.find(search_string) != std::string::npos; - EXPECT_EQ(ping_expected, ping_found) << "query was: " << url1_query - << " was looking for " << search_string; // Make sure the non-google query has no brand parameter. const std::string brand_string = "brand%3D"; @@ -1787,14 +1797,10 @@ class ExtensionUpdaterTest : public testing::Test { // This lets us run a test with some enabled and some disabled // extensions. The |num_enabled| value specifies how many enabled extensions // to have, and |disabled| is a vector of DisableReason bitmasks for each - // disabled extension we want. |enable_metrics| specifies whether we should - // have enabled/disable reason information in the ping parameter. - void TestPingMetrics(bool enable_metrics, - int num_enabled, + // disabled extension we want. + void TestPingMetrics(int num_enabled, const std::vector& disabled) { ServiceForManifestTests service(prefs_.get()); - service.set_enable_metrics(enable_metrics); - ExtensionList enabled_extensions; ExtensionList disabled_extensions; @@ -1849,16 +1855,10 @@ class ExtensionUpdaterTest : public testing::Test { std::map all_pings = GetPingDataFromURL(url); // Make sure that all the enabled extensions have "e=1" in their ping - // parameter if metrics are turned on, or don't have it if metrics are - // off. + // parameter. for (const auto& ext : enabled_extensions) { ASSERT_TRUE(ContainsKey(all_pings, ext->id())); ParamsMap& ping = all_pings[ext->id()]; - if (!enable_metrics) { - EXPECT_FALSE(ContainsKey(ping, "e")); - EXPECT_FALSE(ContainsKey(ping, "dr")); - continue; - } EXPECT_FALSE(ContainsKey(ping, "dr")); ASSERT_TRUE(ContainsKey(ping, "e")) << url; std::set e = ping["e"]; @@ -1877,11 +1877,6 @@ class ExtensionUpdaterTest : public testing::Test { ASSERT_TRUE(ContainsKey(all_pings, ext->id())) << url; ParamsMap& ping = all_pings[ext->id()]; - if (!enable_metrics) { - EXPECT_FALSE(ContainsKey(ping, "e")); - EXPECT_FALSE(ContainsKey(ping, "dr")); - continue; - } ASSERT_TRUE(ContainsKey(ping, "e")) << url; std::set e = ping["e"]; ASSERT_EQ(1u, e.size()) << url; @@ -2238,21 +2233,18 @@ TEST_F(ExtensionUpdaterTest, TestDisabledReasons1) { disabled.push_back(Extension::DISABLE_USER_ACTION); disabled.push_back(Extension::DISABLE_PERMISSIONS_INCREASE | Extension::DISABLE_CORRUPTED); - TestPingMetrics(true, 1, disabled); - TestPingMetrics(false, 1, disabled); + TestPingMetrics(1, disabled); } TEST_F(ExtensionUpdaterTest, TestDisabledReasons2) { std::vector disabled; - TestPingMetrics(true, 1, disabled); - TestPingMetrics(false, 1, disabled); + TestPingMetrics(1, disabled); } TEST_F(ExtensionUpdaterTest, TestDisabledReasons3) { std::vector disabled; disabled.push_back(0); - TestPingMetrics(true, 0, disabled); - TestPingMetrics(false, 0, disabled); + TestPingMetrics(0, disabled); } // TODO(asargent) - (http://crbug.com/12780) add tests for: diff --git a/chrome/browser/favicon/favicon_handler.cc b/chrome/browser/favicon/favicon_handler.cc index acccc57ca15d3..a1bbe173e233f 100644 --- a/chrome/browser/favicon/favicon_handler.cc +++ b/chrome/browser/favicon/favicon_handler.cc @@ -352,7 +352,8 @@ void FaviconHandler::ProcessCurrentUrl() { if (PageChangedSinceFaviconWasRequested() || !current_candidate()) return; - if (current_candidate()->icon_type == favicon_base::FAVICON) { + if (current_candidate()->icon_type == favicon_base::FAVICON && + !download_largest_icon_) { if (!favicon_expired_or_incomplete_ && driver_->GetActiveFaviconValidity() && DoUrlAndIconMatch(*current_candidate(), @@ -538,7 +539,7 @@ void FaviconHandler::OnFaviconDataForInitialURLFromFaviconService( bool has_valid_result = HasValidResult(favicon_bitmap_results); if (has_results && icon_types_ == favicon_base::FAVICON && - !driver_->GetActiveFaviconValidity() && + !download_largest_icon_ && !driver_->GetActiveFaviconValidity() && (!current_candidate() || DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results))) { if (has_valid_result) { @@ -546,7 +547,7 @@ void FaviconHandler::OnFaviconDataForInitialURLFromFaviconService( // doesn't have an icon. Set the favicon now, and if the favicon turns out // to be expired (or the wrong url) we'll fetch later on. This way the // user doesn't see a flash of the default favicon. - NotifyFaviconAvailable(favicon_bitmap_results, !download_largest_icon_); + NotifyFaviconAvailable(favicon_bitmap_results, true); } else { // If |favicon_bitmap_results| does not have any valid results, treat the // favicon as if it's expired. @@ -575,7 +576,8 @@ void FaviconHandler::OnFaviconDataForInitialURLFromFaviconService( // else we haven't got the icon url. When we get it we'll ask the // renderer to download the icon. - if (has_valid_result && icon_types_ != favicon_base::FAVICON) + if (has_valid_result && + (icon_types_ != favicon_base::FAVICON || download_largest_icon_)) NotifyFaviconAvailable(favicon_bitmap_results, false); } @@ -619,12 +621,13 @@ void FaviconHandler::OnFaviconData(const std::vector< preferred_icon_size(), favicon_bitmap_results); bool has_valid_result = HasValidResult(favicon_bitmap_results); - if (has_results && icon_types_ == favicon_base::FAVICON) { + if (has_results && icon_types_ == favicon_base::FAVICON && + !download_largest_icon_) { if (has_valid_result) { // There is a favicon, set it now. If expired we'll download the current // one again, but at least the user will get some icon instead of the // default and most likely the current one is fine anyway. - NotifyFaviconAvailable(favicon_bitmap_results, !download_largest_icon_); + NotifyFaviconAvailable(favicon_bitmap_results, true); } if (has_expired_or_incomplete_result) { // The favicon is out of date. Request the current one. @@ -643,8 +646,10 @@ void FaviconHandler::OnFaviconData(const std::vector< } history_results_ = favicon_bitmap_results; - if (has_valid_result && icon_types_ != favicon_base::FAVICON) + if (has_valid_result && + (icon_types_ != favicon_base::FAVICON || download_largest_icon_)) { NotifyFaviconAvailable(favicon_bitmap_results, false); + } } int FaviconHandler::ScheduleDownload(const GURL& url, diff --git a/chrome/browser/favicon/favicon_handler_unittest.cc b/chrome/browser/favicon/favicon_handler_unittest.cc index 266d1a8ed7e60..5649f6f229bfb 100644 --- a/chrome/browser/favicon/favicon_handler_unittest.cc +++ b/chrome/browser/favicon/favicon_handler_unittest.cc @@ -191,6 +191,7 @@ class TestFaviconDriver : public FaviconDriver { public: TestFaviconDriver() : favicon_validity_(false), + num_active_favicon_(0), num_favicon_available_(0), update_active_favicon_(false) {} @@ -224,20 +225,22 @@ class TestFaviconDriver : public FaviconDriver { void OnFaviconAvailable(const gfx::Image& image, const GURL& icon_url, bool update_active_favicon) override { + ++num_favicon_available_; available_image_ = image; available_icon_url_ = icon_url; update_active_favicon_ = update_active_favicon; if (!update_active_favicon) return; - ++num_favicon_available_; + ++num_active_favicon_; SetActiveFaviconURL(icon_url); SetActiveFaviconValidity(true); SetActiveFaviconImage(image); } + size_t num_active_favicon() const { return num_active_favicon_; } size_t num_favicon_available() const { return num_favicon_available_; } - + void ResetNumActiveFavicon() { num_active_favicon_ = 0; } void ResetNumFaviconAvailable() { num_favicon_available_ = 0; } void SetActiveURL(GURL url) { url_ = url; } @@ -254,6 +257,9 @@ class TestFaviconDriver : public FaviconDriver { gfx::Image image_; bool favicon_validity_; + // The number of times that NotifyFaviconAvailable() has been called with + // |is_active_favicon| is true. + size_t num_active_favicon_; // The number of times that NotifyFaviconAvailable() has been called. size_t num_favicon_available_; gfx::Image available_image_; @@ -443,7 +449,7 @@ class FaviconHandlerTest : public ChromeRenderViewHostTestHarness { download_handler->SetImageSizes(sizes); download_handler->InvokeCallback(); - if (favicon_driver->num_favicon_available()) + if (favicon_driver->num_active_favicon()) return; } } @@ -452,7 +458,7 @@ class FaviconHandlerTest : public ChromeRenderViewHostTestHarness { TestFaviconHandler* favicon_handler, const GURL& page_url, const std::vector& candidate_icons) { - favicon_driver->ResetNumFaviconAvailable(); + favicon_driver->ResetNumActiveFavicon(); favicon_handler->FetchFavicon(page_url); favicon_handler->history_handler()->InvokeCallback(); @@ -1570,4 +1576,86 @@ TEST_F(FaviconHandlerTest, UnableToDownloadFavicon) { EXPECT_FALSE(favicon_service->WasUnableToDownloadFavicon(missing_icon_url)); } +class FaviconHandlerActiveFaviconValidityParamTest : + public FaviconHandlerTest, + public ::testing::WithParamInterface { + public: + FaviconHandlerActiveFaviconValidityParamTest() {} + + ~FaviconHandlerActiveFaviconValidityParamTest() override {} + + bool GetActiveFaviconValiditySetting() { + return GetParam(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(FaviconHandlerActiveFaviconValidityParamTest); +}; + +TEST_P(FaviconHandlerActiveFaviconValidityParamTest, + TestDownloadLargestIconDoesNotImpactActiveFaviconValidity) { + const GURL page_url("http://www.google.com"); + + std::vector one_icon; + one_icon.push_back(gfx::Size(15, 15)); + + const GURL old_favicon_url("http://www.google.com/old"); + const GURL new_favicon_url("http://www.google.com/b"); + const FaviconURL source_icon_urls[] = { + FaviconURL(new_favicon_url, favicon_base::FAVICON, one_icon)}; + TestFaviconClient client; + TestFaviconDriver driver1; + TestFaviconHandler handler1( + page_url, &client, &driver1, FaviconHandler::FAVICON, true); + std::vector urls1(source_icon_urls, + source_icon_urls + arraysize(source_icon_urls)); + UpdateFaviconURL(&driver1, &handler1, page_url, urls1); + + HistoryRequestHandler* history_handler = handler1.history_handler(); + + // Simulate the active favicon is updated, this shouldn't happen in real + // use case, but we want to verify the behavior below is not impacted by + // accident. + driver1.SetActiveFaviconValidity(GetActiveFaviconValiditySetting()); + // Simulate the get favicon from history, but favicon URL didn't match. + SetFaviconRawBitmapResult(old_favicon_url, + &history_handler->history_results_); + history_handler->InvokeCallback(); + // Since we downloaded largest icon, and don't want to set active favicon + // NotifyFaviconAvaliable() should be called with is_active_favicon as false. + EXPECT_EQ(old_favicon_url, driver1.available_icon_url()); + EXPECT_FALSE(driver1.update_active_favicon()); + EXPECT_EQ(1u, driver1.num_favicon_available()); + + // We are trying to get favicon from history again. + history_handler = handler1.history_handler(); + EXPECT_EQ(new_favicon_url, history_handler->icon_url_); + // Simulate the get expired favicon from history. + history_handler->history_results_.clear(); + SetFaviconRawBitmapResult(new_favicon_url, favicon_base::FAVICON, true, + &history_handler->history_results_); + history_handler->InvokeCallback(); + // Since we downloaded largest icon, and don't want to set active favicon + // NotifyFaviconAvaliable() should be called with is_active_favicon as false. + EXPECT_EQ(new_favicon_url, driver1.available_icon_url()); + EXPECT_FALSE(driver1.update_active_favicon()); + EXPECT_EQ(2u, driver1.num_favicon_available()); + + // We are trying to download favicon. + DownloadHandler* download_handler = handler1.download_handler(); + EXPECT_TRUE(download_handler->HasDownload()); + EXPECT_EQ(new_favicon_url, download_handler->GetImageUrl()); + // Simulate the download succeed. + download_handler->InvokeCallback(); + // Since we downloaded largest icon, and don't want to set active favicon + // NotifyFaviconAvaliable() should be called with is_active_favicon as false. + EXPECT_EQ(new_favicon_url, driver1.available_icon_url()); + EXPECT_FALSE(driver1.update_active_favicon()); + EXPECT_EQ(3u, driver1.num_favicon_available()); +} + +INSTANTIATE_TEST_CASE_P(FaviconHandlerTestActiveFaviconValidityTrueOrFalse, + FaviconHandlerActiveFaviconValidityParamTest, + ::testing::Bool()); + } // namespace. diff --git a/chrome/browser/google/did_run_updater_win.cc b/chrome/browser/google/did_run_updater_win.cc new file mode 100644 index 0000000000000..b409fd0a0c6bd --- /dev/null +++ b/chrome/browser/google/did_run_updater_win.cc @@ -0,0 +1,33 @@ +// 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 "chrome/browser/google/did_run_updater_win.h" + +#include "base/base_paths.h" +#include "base/files/file_path.h" +#include "base/path_service.h" +#include "chrome/installer/util/google_update_settings.h" +#include "chrome/installer/util/install_util.h" +#include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_source.h" +#include "content/public/browser/notification_types.h" + +DidRunUpdater::DidRunUpdater() : system_level_(false) { + base::FilePath exe_path; + if (PathService::Get(base::FILE_EXE, &exe_path)) + system_level_ = !InstallUtil::IsPerUserInstall(exe_path.value().c_str()); + + registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED, + content::NotificationService::AllSources()); +} + +DidRunUpdater::~DidRunUpdater() { +} + +void DidRunUpdater::Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + GoogleUpdateSettings::UpdateDidRunState(true, system_level_); +} diff --git a/chrome/browser/google/did_run_updater_win.h b/chrome/browser/google/did_run_updater_win.h new file mode 100644 index 0000000000000..5fb8a6eb905e0 --- /dev/null +++ b/chrome/browser/google/did_run_updater_win.h @@ -0,0 +1,32 @@ +// 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 CHROME_BROWSER_GOOGLE_DID_RUN_UPDATER_WIN_H_ +#define CHROME_BROWSER_GOOGLE_DID_RUN_UPDATER_WIN_H_ + +#include "base/macros.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" + +// Updates Chrome's "did run" state periodically when the process is in use. +// The creation of renderers is used as a proxy for "is the browser in use." +class DidRunUpdater : public content::NotificationObserver { + public: + DidRunUpdater(); + ~DidRunUpdater() override; + + private: + // content::NotificationObserver: + void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) override; + + // True if the process is running from a system-level installation. + bool system_level_; + content::NotificationRegistrar registrar_; + + DISALLOW_COPY_AND_ASSIGN(DidRunUpdater); +}; + +#endif // CHROME_BROWSER_GOOGLE_DID_RUN_UPDATER_WIN_H_ diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc index 24064c6b97b45..4ead3fc028391 100644 --- a/chrome/browser/io_thread.cc +++ b/chrome/browser/io_thread.cc @@ -848,7 +848,7 @@ void IOThread::ConfigureSpdyFromTrial(base::StringPiece spdy_trial_group, globals->use_alternate_protocols.set(true); } else if (spdy_trial_group.starts_with( kSpdyFieldTrialSpdy31GroupNamePrefix)) { - globals->next_protos = net::NextProtosSpdy4Http2(); + globals->next_protos = net::NextProtosSpdy31(); globals->use_alternate_protocols.set(true); } else if (spdy_trial_group.starts_with( kSpdyFieldTrialSpdy4GroupNamePrefix)) { diff --git a/chrome/browser/media/media_stream_devices_controller_browsertest.cc b/chrome/browser/media/media_stream_devices_controller_browsertest.cc index b12c1b7b369f9..57fc46e553966 100644 --- a/chrome/browser/media/media_stream_devices_controller_browsertest.cc +++ b/chrome/browser/media/media_stream_devices_controller_browsertest.cc @@ -7,6 +7,8 @@ #include "base/bind.h" #include "base/prefs/pref_service.h" #include "chrome/browser/content_settings/tab_specific_content_settings.h" +#include "chrome/browser/media/media_capture_devices_dispatcher.h" +#include "chrome/browser/media/media_stream_capture_indicator.h" #include "chrome/browser/media/media_stream_device_permissions.h" #include "chrome/browser/media/media_stream_devices_controller.h" #include "chrome/browser/media/webrtc_browsertest_base.h" @@ -396,3 +398,75 @@ IN_PROC_BROWSER_TEST_F(MediaStreamDevicesControllerTest, EXPECT_EQ(example_audio_id(), GetContentSettings()->media_stream_selected_audio_device()); } + +// Denying mic access after camera access should still show the camera as state. +IN_PROC_BROWSER_TEST_F(MediaStreamDevicesControllerTest, + DenyMicDoesNotChangeCam) { + // Request cam and allow + SetDevicePolicy(DEVICE_TYPE_VIDEO, ACCESS_ALLOWED); + MediaStreamDevicesController cam_controller( + GetWebContents(), + CreateRequest(std::string(), example_video_id()), + base::Bind(&OnMediaStreamResponse)); + NotifyTabSpecificContentSettings(&cam_controller); + EXPECT_TRUE(GetContentSettings()->IsContentAllowed( + CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA)); + EXPECT_FALSE(GetContentSettings()->IsContentBlocked( + CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA)); + EXPECT_EQ(example_video_id(), + GetContentSettings()->media_stream_requested_video_device()); + EXPECT_EQ(example_video_id(), + GetContentSettings()->media_stream_selected_video_device()); + EXPECT_EQ(TabSpecificContentSettings::CAMERA_ACCESSED, + GetContentSettings()->GetMicrophoneCameraState()); + + // Simulate that an a video stream is now being captured. + content::MediaStreamDevice fake_video_device( + content::MEDIA_DEVICE_VIDEO_CAPTURE, example_video_id(), + example_video_id()); + content::MediaStreamDevices video_devices(1, fake_video_device); + MediaCaptureDevicesDispatcher* dispatcher = + MediaCaptureDevicesDispatcher::GetInstance(); + dispatcher->SetTestVideoCaptureDevices(video_devices); + scoped_ptr video_stream_ui = + dispatcher->GetMediaStreamCaptureIndicator()-> + RegisterMediaStream(GetWebContents(), video_devices); + video_stream_ui->OnStarted(base::Closure()); + + // Request mic and deny. + SetDevicePolicy(DEVICE_TYPE_AUDIO, ACCESS_DENIED); + MediaStreamDevicesController mic_controller( + GetWebContents(), + CreateRequest(example_audio_id(), std::string()), + base::Bind(&OnMediaStreamResponse)); + NotifyTabSpecificContentSettings(&mic_controller); + EXPECT_FALSE(GetContentSettings()->IsContentAllowed( + CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC)); + EXPECT_TRUE(GetContentSettings()->IsContentBlocked( + CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC)); + EXPECT_EQ(example_audio_id(), + GetContentSettings()->media_stream_requested_audio_device()); + EXPECT_EQ(example_audio_id(), + GetContentSettings()->media_stream_selected_audio_device()); + + // Cam should still be included in the state. + EXPECT_TRUE(GetContentSettings()->IsContentAllowed( + CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA)); + EXPECT_FALSE(GetContentSettings()->IsContentBlocked( + CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA)); + EXPECT_EQ(example_video_id(), + GetContentSettings()->media_stream_requested_video_device()); + EXPECT_EQ(example_video_id(), + GetContentSettings()->media_stream_selected_video_device()); + EXPECT_EQ(TabSpecificContentSettings::MICROPHONE_ACCESSED | + TabSpecificContentSettings::MICROPHONE_BLOCKED | + TabSpecificContentSettings::CAMERA_ACCESSED, + GetContentSettings()->GetMicrophoneCameraState()); + + // After ending the camera capture, the camera permission is no longer + // relevant, so it should no be included in the mic/cam state. + video_stream_ui.reset(); + EXPECT_EQ(TabSpecificContentSettings::MICROPHONE_ACCESSED | + TabSpecificContentSettings::MICROPHONE_BLOCKED, + GetContentSettings()->GetMicrophoneCameraState()); +} diff --git a/chrome/browser/metrics/metrics_reporting_state.cc b/chrome/browser/metrics/metrics_reporting_state.cc index 07dfdaef6c037..a4a61feab95f0 100644 --- a/chrome/browser/metrics/metrics_reporting_state.cc +++ b/chrome/browser/metrics/metrics_reporting_state.cc @@ -62,6 +62,12 @@ void SetMetricsReporting(bool to_update_pref, g_browser_process->local_state()->SetBoolean( prefs::kMetricsReportingEnabled, updated_pref); #endif + // When a user opts in to the metrics reporting service, the previously + // collected data should be cleared to ensure that nothing is reported before + // a user opts in and all reported data is accurate. + if (updated_pref && metrics) + metrics->ClearSavedStabilityMetrics(); + if (to_update_pref == updated_pref) { RecordMetricsReportingHistogramValue(updated_pref ? METRICS_REPORTING_ENABLED : METRICS_REPORTING_DISABLED); diff --git a/chrome/browser/net/chrome_network_delegate.cc b/chrome/browser/net/chrome_network_delegate.cc index f2e1d77d84628..e9c0892bb70bb 100644 --- a/chrome/browser/net/chrome_network_delegate.cc +++ b/chrome/browser/net/chrome_network_delegate.cc @@ -326,9 +326,9 @@ void ChromeNetworkDelegate::AllowAccessToAllFiles() { // static // TODO(megjablon): Use data_reduction_proxy_delayed_pref_service to read prefs. // Until updated the pref values may be up to an hour behind on desktop. -base::Value* ChromeNetworkDelegate::HistoricNetworkStatsInfoToValue() { +base::Value* ChromeNetworkDelegate::HistoricNetworkStatsInfoToValue( + PrefService* prefs) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - PrefService* prefs = g_browser_process->local_state(); int64 total_received = prefs->GetInt64( data_reduction_proxy::prefs::kHttpReceivedContentLength); int64 total_original = prefs->GetInt64( diff --git a/chrome/browser/net/chrome_network_delegate.h b/chrome/browser/net/chrome_network_delegate.h index 8e5b7de058dd5..8a13b1eb58437 100644 --- a/chrome/browser/net/chrome_network_delegate.h +++ b/chrome/browser/net/chrome_network_delegate.h @@ -209,7 +209,7 @@ class ChromeNetworkDelegate : public net::NetworkDelegate { // Creates a Value summary of the persistent state of the network session. // The caller is responsible for deleting the returned value. // Must be called on the UI thread. - static base::Value* HistoricNetworkStatsInfoToValue(); + static base::Value* HistoricNetworkStatsInfoToValue(PrefService* prefs); // Creates a Value summary of the state of the network session. The caller is // responsible for deleting the returned value. diff --git a/chrome/browser/notifications/notification_ui_manager_android.cc b/chrome/browser/notifications/notification_ui_manager_android.cc index b440197981a9c..a11aaf175c2fa 100644 --- a/chrome/browser/notifications/notification_ui_manager_android.cc +++ b/chrome/browser/notifications/notification_ui_manager_android.cc @@ -4,9 +4,18 @@ #include "chrome/browser/notifications/notification_ui_manager_android.h" +#include "base/android/jni_string.h" #include "base/logging.h" #include "base/strings/string16.h" #include "chrome/browser/notifications/profile_notification.h" +#include "jni/NotificationUIManager_jni.h" +#include "ui/gfx/android/java_bitmap.h" +#include "ui/gfx/image/image.h" + +using base::android::AttachCurrentThread; +using base::android::ConvertJavaStringToUTF8; +using base::android::ConvertUTF16ToJavaString; +using base::android::ConvertUTF8ToJavaString; // static NotificationUIManager* NotificationUIManager::Create(PrefService* local_state) { @@ -14,9 +23,37 @@ NotificationUIManager* NotificationUIManager::Create(PrefService* local_state) { } NotificationUIManagerAndroid::NotificationUIManagerAndroid() { + java_object_.Reset( + Java_NotificationUIManager_create( + AttachCurrentThread(), + reinterpret_cast(this), + base::android::GetApplicationContext())); +} + +NotificationUIManagerAndroid::~NotificationUIManagerAndroid() {} + +void NotificationUIManagerAndroid::OnNotificationClicked( + JNIEnv* env, jobject java_object, jstring notification_id) { + std::string id = ConvertJavaStringToUTF8(env, notification_id); + + auto iter = profile_notifications_.find(id); + if (iter == profile_notifications_.end()) + return; + + const Notification& notification = iter->second->notification(); + notification.delegate()->Click(); } -NotificationUIManagerAndroid::~NotificationUIManagerAndroid() { +void NotificationUIManagerAndroid::OnNotificationClosed( + JNIEnv* env, jobject java_object, jstring notification_id) { + std::string id = ConvertJavaStringToUTF8(env, notification_id); + + auto iter = profile_notifications_.find(id); + if (iter == profile_notifications_.end()) + return; + + const Notification& notification = iter->second->notification(); + notification.delegate()->Close(true /** by_user **/); } void NotificationUIManagerAndroid::Add(const Notification& notification, @@ -30,7 +67,25 @@ void NotificationUIManagerAndroid::Add(const Notification& notification, // Takes ownership of |profile_notification|. AddProfileNotification(profile_notification); - // TODO(peter): Display the notification on the Android system. + JNIEnv* env = AttachCurrentThread(); + + ScopedJavaLocalRef id = ConvertUTF8ToJavaString( + env, profile_notification->notification().id()); + ScopedJavaLocalRef title = ConvertUTF16ToJavaString( + env, notification.title()); + ScopedJavaLocalRef body = ConvertUTF16ToJavaString( + env, notification.message()); + + SkBitmap icon_bitmap = notification.icon().AsBitmap(); + ScopedJavaLocalRef icon = gfx::ConvertToJavaBitmap(&icon_bitmap); + + int platform_id = Java_NotificationUIManager_displayNotification( + env, java_object_.obj(), id.obj(), title.obj(), body.obj(), icon.obj()); + + std::string notification_id = profile_notification->notification().id(); + platform_notifications_[notification_id] = platform_id; + + notification.delegate()->Display(); } bool NotificationUIManagerAndroid::Update(const Notification& notification, @@ -152,9 +207,24 @@ void NotificationUIManagerAndroid::CancelAll() { profile_notifications_.clear(); } +bool NotificationUIManagerAndroid::RegisterNotificationUIManager(JNIEnv* env) { + return RegisterNativesImpl(env); +} + void NotificationUIManagerAndroid::PlatformCloseNotification( - ProfileNotification* notification) const { - // TODO(peter): Remove the notification from the Android system. + ProfileNotification* profile_notification) { + std::string id = profile_notification->notification().id(); + + auto iterator = platform_notifications_.find(id); + if (iterator == platform_notifications_.end()) + return; + + int platform_id = iterator->second; + platform_notifications_.erase(id); + + Java_NotificationUIManager_closeNotification(AttachCurrentThread(), + java_object_.obj(), + platform_id); } void NotificationUIManagerAndroid::AddProfileNotification( @@ -184,3 +254,4 @@ ProfileNotification* NotificationUIManagerAndroid::FindProfileNotification( return iter->second; } + diff --git a/chrome/browser/notifications/notification_ui_manager_android.h b/chrome/browser/notifications/notification_ui_manager_android.h index 7d37e242690bd..d9f7f36a6cda6 100644 --- a/chrome/browser/notifications/notification_ui_manager_android.h +++ b/chrome/browser/notifications/notification_ui_manager_android.h @@ -5,10 +5,12 @@ #ifndef CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_UI_MANAGER_ANDROID_H_ #define CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_UI_MANAGER_ANDROID_H_ +#include #include #include #include +#include "base/android/scoped_java_ref.h" #include "chrome/browser/notifications/notification_ui_manager.h" class ProfileNotification; @@ -20,6 +22,16 @@ class NotificationUIManagerAndroid : public NotificationUIManager { NotificationUIManagerAndroid(); ~NotificationUIManagerAndroid() override; + // Called by the Java implementation when a notification has been clicked on. + void OnNotificationClicked(JNIEnv* env, + jobject java_object, + jstring notification_id); + + // Called by the Java implementation when a notification has been closed. + void OnNotificationClosed(JNIEnv* env, + jobject java_object, + jstring notification_id); + // NotificationUIManager implementation; void Add(const Notification& notification, Profile* profile) override; bool Update(const Notification& notification, @@ -35,9 +47,11 @@ class NotificationUIManagerAndroid : public NotificationUIManager { bool CancelAllByProfile(ProfileID profile_id) override; void CancelAll() override; + static bool RegisterNotificationUIManager(JNIEnv* env); + private: // Closes the Notification as displayed on the Android system. - void PlatformCloseNotification(ProfileNotification* notification) const; + void PlatformCloseNotification(ProfileNotification* profile_notification); // Helpers that add/remove the notification from local map. // The local map takes ownership of profile_notification object. @@ -51,6 +65,11 @@ class NotificationUIManagerAndroid : public NotificationUIManager { // Map from a notification id to the associated ProfileNotification*. std::map profile_notifications_; + // Map from notification id to the associated platform Id. + std::map platform_notifications_; + + base::android::ScopedJavaGlobalRef java_object_; + DISALLOW_COPY_AND_ASSIGN(NotificationUIManagerAndroid); }; diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc index 029008d5f73ea..d6e4a3f3cfe96 100644 --- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc +++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc @@ -27,6 +27,10 @@ #include "components/translate/core/common/translate_pref_names.h" #include "policy/policy_constants.h" +#if defined(OS_ANDROID) +#include "chrome/browser/search/contextual_search_policy_handler_android.h" +#endif + #if !defined(OS_IOS) #include "chrome/browser/net/disk_cache_dir_policy_handler.h" #include "chrome/browser/policy/file_selection_dialogs_policy_handler.h" @@ -575,6 +579,11 @@ scoped_ptr BuildHandlerList( handlers->AddHandler(make_scoped_ptr( new URLBlacklistPolicyHandler())); +#if defined(OS_ANDROID) + handlers->AddHandler(make_scoped_ptr( + new ContextualSearchPolicyHandlerAndroid())); +#endif + #if !defined(OS_IOS) handlers->AddHandler(make_scoped_ptr( new FileSelectionDialogsPolicyHandler())); diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 56bac851e39d6..6ea64fff988bc 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc @@ -65,6 +65,7 @@ #include "chrome/browser/ui/browser_ui_prefs.h" #include "chrome/browser/ui/navigation_correction_tab_observer.h" #include "chrome/browser/ui/network_profile_bubble.h" +#include "chrome/browser/ui/passwords/password_bubble_experiment.h" #include "chrome/browser/ui/prefs/prefs_tab_helper.h" #include "chrome/browser/ui/search_engines/keyword_editor_controller.h" #include "chrome/browser/ui/startup/autolaunch_prompt.h" @@ -407,6 +408,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { MediaStreamDevicesController::RegisterProfilePrefs(registry); NetPrefObserver::RegisterProfilePrefs(registry); password_manager::PasswordManager::RegisterProfilePrefs(registry); + password_bubble_experiment::RegisterPrefs(registry); PrefProxyConfigTrackerImpl::RegisterProfilePrefs(registry); PrefsTabHelper::RegisterProfilePrefs(registry); Profile::RegisterProfilePrefs(registry); diff --git a/chrome/browser/renderer_preferences_util.cc b/chrome/browser/renderer_preferences_util.cc index fc0ada5e4f008..bf1e2e082c618 100644 --- a/chrome/browser/renderer_preferences_util.cc +++ b/chrome/browser/renderer_preferences_util.cc @@ -22,7 +22,6 @@ #endif #if defined(TOOLKIT_VIEWS) -#include "chrome/browser/defaults.h" #include "ui/views/controls/textfield/textfield.h" #endif @@ -70,14 +69,6 @@ void UpdateFromSystemSettings(content::RendererPreferences* prefs, #if defined(TOOLKIT_VIEWS) prefs->caret_blink_interval = views::Textfield::GetCaretBlinkMs() / 1000.0; - if (browser_defaults::kShowLinkDisambiguationPopup) { - prefs->tap_multiple_targets_strategy = - content::TapMultipleTargetsStrategy:: - TAP_MULTIPLE_TARGETS_STRATEGY_POPUP; - } else { - prefs->tap_multiple_targets_strategy = - content::TapMultipleTargetsStrategy::TAP_MULTIPLE_TARGETS_STRATEGY_NONE; - } #endif #if defined(USE_AURA) && defined(OS_LINUX) && !defined(OS_CHROMEOS) diff --git a/chrome/browser/resources/chromeos/genius_app/manifest.json b/chrome/browser/resources/chromeos/genius_app/manifest.json index 2f663e0359eb6..84f38e9784a04 100644 --- a/chrome/browser/resources/chromeos/genius_app/manifest.json +++ b/chrome/browser/resources/chromeos/genius_app/manifest.json @@ -6,6 +6,7 @@ "version": "0.2", "minimum_chrome_version": "28", "default_locale": "en", + "incognito" : "split", "icons": { "16": "icon/16.png", "32": "icon/32.png", diff --git a/chrome/browser/resources/component_extension_resources.grd b/chrome/browser/resources/component_extension_resources.grd index 7592e3313ab9b..2779d01fb1e41 100644 --- a/chrome/browser/resources/component_extension_resources.grd +++ b/chrome/browser/resources/component_extension_resources.grd @@ -216,6 +216,7 @@ + diff --git a/chrome/browser/resources/cryptotoken/countdowntimer.js b/chrome/browser/resources/cryptotoken/countdowntimer.js index d65bc2e9c9c78..1ce31d03b0526 100644 --- a/chrome/browser/resources/cryptotoken/countdowntimer.js +++ b/chrome/browser/resources/cryptotoken/countdowntimer.js @@ -117,18 +117,20 @@ CountdownTimerFactory.prototype.createTimer = * guaranteed, in seconds. * @const */ -var MINIMUM_TIMEOUT_ATTENUATION_SECONDS = 0.5; +var MINIMUM_TIMEOUT_ATTENUATION_SECONDS = 1; /** * @param {number} timeoutSeconds Timeout value in seconds. + * @param {number=} opt_attenuationSeconds Attenuation value in seconds. * @return {number} The timeout value, attenuated to ensure a response can be * given before the timeout's expiration. - * @private */ -function attenuateTimeoutInSeconds_(timeoutSeconds) { - if (timeoutSeconds < MINIMUM_TIMEOUT_ATTENUATION_SECONDS) +function attenuateTimeoutInSeconds(timeoutSeconds, opt_attenuationSeconds) { + var attenuationSeconds = + opt_attenuationSeconds || MINIMUM_TIMEOUT_ATTENUATION_SECONDS; + if (timeoutSeconds < attenuationSeconds) return 0; - return timeoutSeconds - MINIMUM_TIMEOUT_ATTENUATION_SECONDS; + return timeoutSeconds - attenuationSeconds; } /** @@ -138,15 +140,14 @@ function attenuateTimeoutInSeconds_(timeoutSeconds) { var DEFAULT_REQUEST_TIMEOUT_SECONDS = 30; /** - * Creates a new countdown from the given request using the given timer factory, - * attenuated to ensure a response is given prior to the countdown's expiration. - * @param {CountdownFactory} timerFactory The factory to use. + * Gets the timeout value from the request, if any, substituting + * opt_defaultTimeoutSeconds or DEFAULT_REQUEST_TIMEOUT_SECONDS if the request + * does not contain a timeout value. * @param {Object} request The request containing the timeout. * @param {number=} opt_defaultTimeoutSeconds - * @return {!Countdown} A countdown timer. + * @return {number} Timeout value, in seconds. */ -function createTimerForRequest(timerFactory, request, - opt_defaultTimeoutSeconds) { +function getTimeoutValueFromRequest(request, opt_defaultTimeoutSeconds) { var timeoutValueSeconds; if (request.hasOwnProperty('timeoutSeconds')) { timeoutValueSeconds = request['timeoutSeconds']; @@ -157,6 +158,21 @@ function createTimerForRequest(timerFactory, request, } else { timeoutValueSeconds = DEFAULT_REQUEST_TIMEOUT_SECONDS; } - timeoutValueSeconds = attenuateTimeoutInSeconds_(timeoutValueSeconds); + return timeoutValueSeconds; +} + +/** + * Creates a new countdown for the given timeout value, attenuated to ensure a + * response is given prior to the countdown's expiration, using the given timer + * factory. + * @param {CountdownFactory} timerFactory The factory to use. + * @param {number} timeoutValueSeconds + * @param {number=} opt_attenuationSeconds Attenuation value in seconds. + * @return {!Countdown} A countdown timer. + */ +function createAttenuatedTimer(timerFactory, timeoutValueSeconds, + opt_attenuationSeconds) { + timeoutValueSeconds = attenuateTimeoutInSeconds(timeoutValueSeconds, + opt_attenuationSeconds); return timerFactory.createTimer(timeoutValueSeconds * 1000); } diff --git a/chrome/browser/resources/cryptotoken/enroller.js b/chrome/browser/resources/cryptotoken/enroller.js index 867dab7763787..1ee758e663560 100644 --- a/chrome/browser/resources/cryptotoken/enroller.js +++ b/chrome/browser/resources/cryptotoken/enroller.js @@ -138,8 +138,9 @@ function validateEnrollRequest(sender, request, return null; } - var timer = createTimerForRequest( - FACTORY_REGISTRY.getCountdownFactory(), request); + var timeoutValueSeconds = getTimeoutValueFromRequest(request); + var timer = createAttenuatedTimer( + FACTORY_REGISTRY.getCountdownFactory(), timeoutValueSeconds); var logMsgUrl = request['logMsgUrl']; var enroller = new Enroller(timer, sender, errorCb, successCb, logMsgUrl); return enroller; diff --git a/chrome/browser/resources/cryptotoken/manifest.json b/chrome/browser/resources/cryptotoken/manifest.json index 71bfd917862aa..ac7386203aabf 100644 --- a/chrome/browser/resources/cryptotoken/manifest.json +++ b/chrome/browser/resources/cryptotoken/manifest.json @@ -1,7 +1,7 @@ { "name": "CryptoTokenExtension", "description": "CryptoToken Component Extension", - "version": "0.9.2", + "version": "0.9.6", "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq7zRobvA+AVlvNqkHSSVhh1sEWsHSqz4oR/XptkDe/Cz3+gW9ZGumZ20NCHjaac8j1iiesdigp8B1LJsd/2WWv2Dbnto4f8GrQ5MVphKyQ9WJHwejEHN2K4vzrTcwaXqv5BSTXwxlxS/mXCmXskTfryKTLuYrcHEWK8fCHb+0gvr8b/kvsi75A1aMmb6nUnFJvETmCkOCPNX5CHTdy634Ts/x0fLhRuPlahk63rdf7agxQv5viVjQFk+tbgv6aa9kdSd11Js/RZ9yZjrFgHOBWgP4jTBqud4+HUglrzu8qynFipyNRLCZsaxhm+NItTyNgesxLdxZcwOz56KD1Q4IQIDAQAB", "manifest_version": 2, "permissions": [ @@ -55,6 +55,7 @@ "origincheck.js", "textfetcher.js", "appid.js", + "watchdog.js", "gstaticorigincheck.js", "googleapprovedorigins.js", "gnubbydevice.js", diff --git a/chrome/browser/resources/cryptotoken/requestqueue.js b/chrome/browser/resources/cryptotoken/requestqueue.js index a878d7a9602f6..9c523eaf7f3ae 100644 --- a/chrome/browser/resources/cryptotoken/requestqueue.js +++ b/chrome/browser/resources/cryptotoken/requestqueue.js @@ -20,6 +20,7 @@ QueuedRequestToken.prototype.complete = function() {}; /** * @param {!RequestQueue} queue The queue for this request. + * @param {number} id An id for this request. * @param {function(QueuedRequestToken)} beginCb Called when work may begin on * this request. * @param {RequestToken} opt_prev Previous request in the same queue. @@ -27,9 +28,11 @@ QueuedRequestToken.prototype.complete = function() {}; * @constructor * @implements {QueuedRequestToken} */ -function RequestToken(queue, beginCb, opt_prev, opt_next) { +function RequestToken(queue, id, beginCb, opt_prev, opt_next) { /** @private {!RequestQueue} */ this.queue_ = queue; + /** @private {number} */ + this.id_ = id; /** @type {function(QueuedRequestToken)} */ this.beginCb = beginCb; /** @type {RequestToken} */ @@ -64,6 +67,8 @@ function RequestQueue() { this.head_ = null; /** @private {RequestToken} */ this.tail_ = null; + /** @private {number} */ + this.id_ = 0; } /** @@ -72,6 +77,7 @@ function RequestQueue() { * @private */ RequestQueue.prototype.insertToken_ = function(token) { + console.log(UTIL_fmt('token ' + this.id_ + ' inserted')); if (this.head_ === null) { this.head_ = token; this.tail_ = token; @@ -116,6 +122,7 @@ RequestQueue.prototype.removeToken_ = function(token) { * @param {RequestToken} token Queue token */ RequestQueue.prototype.complete = function(token) { + console.log(UTIL_fmt('token ' + this.id_ + ' completed')); var next = token.next; this.removeToken_(token); if (next) { @@ -137,7 +144,7 @@ RequestQueue.prototype.empty = function() { */ RequestQueue.prototype.queueRequest = function(beginCb, timer) { var startNow = this.empty(); - var token = new RequestToken(this, beginCb); + var token = new RequestToken(this, ++this.id_, beginCb); // Clone the timer to set a callback on it, which will ensure complete() is // eventually called, even if the caller never gets around to it. timer.clone(token.complete.bind(token)); @@ -171,7 +178,7 @@ function OriginKeyedRequestQueue() { */ OriginKeyedRequestQueue.prototype.queueRequest = function(appId, origin, beginCb, timer) { - var key = appId + origin; + var key = appId + ' ' + origin; if (!this.requests_.hasOwnProperty(key)) { this.requests_[key] = new RequestQueue(); } diff --git a/chrome/browser/resources/cryptotoken/signer.js b/chrome/browser/resources/cryptotoken/signer.js index 3277447f69029..f0af2a17ed4f6 100644 --- a/chrome/browser/resources/cryptotoken/signer.js +++ b/chrome/browser/resources/cryptotoken/signer.js @@ -143,6 +143,10 @@ function addSignatureAndBrowserDataToResponseData(responseData, signatureData, */ function validateAndEnqueueSignRequest(sender, request, signChallengesName, errorCb, successCb) { + function timeout() { + errorCb({errorCode: ErrorCodes.TIMEOUT}); + } + if (!isValidSignRequest(request, signChallengesName)) { errorCb({errorCode: ErrorCodes.BAD_REQUEST}); return null; @@ -161,19 +165,31 @@ function validateAndEnqueueSignRequest(sender, request, errorCb({errorCode: ErrorCodes.BAD_REQUEST}); return null; } - var timer = createTimerForRequest( - FACTORY_REGISTRY.getCountdownFactory(), request); + var timeoutValueSeconds = getTimeoutValueFromRequest(request); + // Attenuate watchdog timeout value less than the signer's timeout, so the + // watchdog only fires after the signer could reasonably have called back, + // not before. + timeoutValueSeconds = attenuateTimeoutInSeconds(timeoutValueSeconds, + MINIMUM_TIMEOUT_ATTENUATION_SECONDS / 2); + var watchdog = new WatchdogRequestHandler(timeoutValueSeconds, timeout); + var wrappedErrorCb = watchdog.wrapCallback(errorCb); + var wrappedSuccessCb = watchdog.wrapCallback(successCb); + + var timer = createAttenuatedTimer( + FACTORY_REGISTRY.getCountdownFactory(), timeoutValueSeconds); var logMsgUrl = request['logMsgUrl']; // Queue sign requests from the same origin, to protect against simultaneous // sign-out on many tabs resulting in repeated sign-in requests. var queuedSignRequest = new QueuedSignRequest(signChallenges, - timer, sender, errorCb, successCb, request['challenge'], + timer, sender, wrappedErrorCb, wrappedSuccessCb, request['challenge'], appId, logMsgUrl); var requestToken = signRequestQueue.queueRequest(appId, sender.origin, queuedSignRequest.begin.bind(queuedSignRequest), timer); queuedSignRequest.setToken(requestToken); - return queuedSignRequest; + + watchdog.setCloseable(queuedSignRequest); + return watchdog; } /** @@ -216,7 +232,7 @@ function QueuedSignRequest(signChallenges, timer, sender, errorCb, /** @private {!Array.} */ this.signChallenges_ = signChallenges; /** @private {Countdown} */ - this.timer_ = timer; + this.timer_ = timer.clone(this.close.bind(this)); /** @private {WebRequestSender} */ this.sender_ = sender; /** @private {function(U2fError)} */ @@ -238,10 +254,17 @@ function QueuedSignRequest(signChallenges, timer, sender, errorCb, /** Closes this sign request. */ QueuedSignRequest.prototype.close = function() { if (this.closed_) return; + var hadBegunSigning = false; if (this.begun_ && this.signer_) { this.signer_.close(); + hadBegunSigning = true; } if (this.token_) { + if (hadBegunSigning) { + console.log(UTIL_fmt('closing in-progress request')); + } else { + console.log(UTIL_fmt('closing timed-out request before processing')); + } this.token_.complete(); } this.closed_ = true; @@ -260,6 +283,12 @@ QueuedSignRequest.prototype.setToken = function(token) { * @param {QueuedRequestToken} token Token for this sign request. */ QueuedSignRequest.prototype.begin = function(token) { + if (this.timer_.expired()) { + console.log(UTIL_fmt('Queued request begun after timeout')); + this.close(); + this.errorCb_({errorCode: ErrorCodes.TIMEOUT}); + return; + } this.begun_ = true; this.setToken(token); this.signer_ = new Signer(this.timer_, this.sender_, @@ -270,6 +299,8 @@ QueuedSignRequest.prototype.begin = function(token) { token.complete(); this.errorCb_({errorCode: ErrorCodes.BAD_REQUEST}); } + // Signer now has responsibility for maintaining timeout. + this.timer_.clearTimeout(); }; /** @@ -307,7 +338,7 @@ QueuedSignRequest.prototype.signerSucceeded_ = */ function Signer(timer, sender, errorCb, successCb, opt_logMsgUrl) { /** @private {Countdown} */ - this.timer_ = timer; + this.timer_ = timer.clone(); /** @private {WebRequestSender} */ this.sender_ = sender; /** @private {function(U2fError)} */ @@ -347,6 +378,10 @@ Signer.prototype.setChallenges = function(signChallenges, opt_defaultChallenge, opt_appId) { if (this.challengesSet_ || this.done_) return false; + if (this.timer_.expired()) { + this.notifyError_({errorCode: ErrorCodes.TIMEOUT}); + return true; + } /** @private {Array.} */ this.signChallenges_ = signChallenges; /** @private {string|undefined} */ @@ -483,6 +518,17 @@ Signer.prototype.getChallengeHash_ = function(keyHandle, challenge) { /** Closes this signer. */ Signer.prototype.close = function() { + this.close_(); +}; + +/** + * Closes this signer, and optionally notifies the caller of error. + * @param {boolean=} opt_notifying When true, this method is being called in the + * process of notifying the caller of an existing status. When false, + * the caller is notified with a default error value, ErrorCodes.TIMEOUT. + * @private + */ +Signer.prototype.close_ = function(opt_notifying) { if (this.appIdChecker_) { this.appIdChecker_.close(); } @@ -491,6 +537,9 @@ Signer.prototype.close = function() { this.handler_ = null; } this.timer_.clearTimeout(); + if (!opt_notifying) { + this.notifyError_({errorCode: ErrorCodes.TIMEOUT}); + } }; /** @@ -501,8 +550,8 @@ Signer.prototype.close = function() { Signer.prototype.notifyError_ = function(error) { if (this.done_) return; - this.close(); this.done_ = true; + this.close_(true); this.errorCb_(error); }; @@ -516,8 +565,8 @@ Signer.prototype.notifyError_ = function(error) { Signer.prototype.notifySuccess_ = function(challenge, info, browserData) { if (this.done_) return; - this.close(); this.done_ = true; + this.close_(true); this.successCb_(challenge, info, browserData); }; diff --git a/chrome/browser/resources/cryptotoken/singlesigner.js b/chrome/browser/resources/cryptotoken/singlesigner.js index 5538ff7bc70ec..d2f2333a81355 100644 --- a/chrome/browser/resources/cryptotoken/singlesigner.js +++ b/chrome/browser/resources/cryptotoken/singlesigner.js @@ -345,12 +345,20 @@ SingleGnubbySigner.prototype.signCallback_ = break; case DeviceStatusCodes.TIMEOUT_STATUS: - // TODO: On a TIMEOUT_STATUS, sync first, then retry. + this.gnubby_.sync(this.synced_.bind(this)); + break; + case DeviceStatusCodes.BUSY_STATUS: this.doSign_(this.challengeIndex_); break; case DeviceStatusCodes.OK_STATUS: + // Lower bound on the minimum length, signature length can vary. + var MIN_SIGNATURE_LENGTH = 7; + if (!opt_info || opt_info.byteLength < MIN_SIGNATURE_LENGTH) { + console.error(UTIL_fmt('Got short response to sign request (' + + (opt_info ? opt_info.byteLength : 0) + ' bytes), WTF?')); + } if (this.forEnroll_) { this.goToError_(code); } else { @@ -386,6 +394,20 @@ SingleGnubbySigner.prototype.signCallback_ = } }; +/** + * Called with the response of a sync command, called when a sign yields a + * timeout to reassert control over the gnubby. + * @param {number} code Error code + * @private + */ +SingleGnubbySigner.prototype.synced_ = function(code) { + if (code) { + this.goToError_(code, true); + return; + } + this.doSign_(this.challengeIndex_); +}; + /** * Switches to the error state, and notifies caller. * @param {number} code Error code diff --git a/chrome/browser/resources/cryptotoken/usbsignhandler.js b/chrome/browser/resources/cryptotoken/usbsignhandler.js index 560ca59a7a0a4..e5c227e572a3f 100644 --- a/chrome/browser/resources/cryptotoken/usbsignhandler.js +++ b/chrome/browser/resources/cryptotoken/usbsignhandler.js @@ -122,7 +122,20 @@ UsbSignHandler.BOGUS_APP_ID_HASH = [ ]; /** @const */ -UsbSignHandler.BOGUS_CHALLENGE_HASH = [ +UsbSignHandler.BOGUS_CHALLENGE_V1 = [ + 0x04, 0xA2, 0x24, 0x7D, 0x5C, 0x0B, 0x76, 0xF1, + 0xDC, 0xCD, 0x44, 0xAF, 0x91, 0x9A, 0xA2, 0x3F, + 0x3F, 0xBA, 0x65, 0x9F, 0x06, 0x78, 0x82, 0xFB, + 0x93, 0x4B, 0xBF, 0x86, 0x55, 0x95, 0x66, 0x46, + 0x76, 0x90, 0xDC, 0xE1, 0xE8, 0x6C, 0x86, 0x86, + 0xC3, 0x03, 0x4E, 0x65, 0x52, 0x4C, 0x32, 0x6F, + 0xB6, 0x44, 0x0D, 0x50, 0xF9, 0x16, 0xC0, 0xA3, + 0xDA, 0x31, 0x4B, 0xD3, 0x3F, 0x94, 0xA5, 0xF1, + 0xD3 +]; + +/** @const */ +UsbSignHandler.BOGUS_CHALLENGE_V2 = [ 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, @@ -136,10 +149,29 @@ UsbSignHandler.BOGUS_CHALLENGE_HASH = [ * @private */ UsbSignHandler.prototype.sendBogusEnroll_ = function(gnubby) { - gnubby.enroll( - UsbSignHandler.BOGUS_APP_ID_HASH, - UsbSignHandler.BOGUS_CHALLENGE_HASH, - this.enrollCallback_.bind(this, gnubby)); + var self = this; + gnubby.version(function(rc, opt_data) { + if (rc) { + self.notifyError_(rc); + return; + } + var enrollChallenge; + var version = UTIL_BytesToString(new Uint8Array(opt_data || [])); + switch (version) { + case Gnubby.U2F_V1: + enrollChallenge = UsbSignHandler.BOGUS_CHALLENGE_V1; + break; + case Gnubby.U2F_V2: + enrollChallenge = UsbSignHandler.BOGUS_CHALLENGE_V2; + break; + default: + self.notifyError_(DeviceStatusCodes.INVALID_DATA_STATUS); + } + gnubby.enroll( + /** @type {Array.} */ (enrollChallenge), + UsbSignHandler.BOGUS_APP_ID_HASH, + self.enrollCallback_.bind(self, gnubby)); + }); }; /** diff --git a/chrome/browser/resources/cryptotoken/watchdog.js b/chrome/browser/resources/cryptotoken/watchdog.js new file mode 100644 index 0000000000000..17bee28722c93 --- /dev/null +++ b/chrome/browser/resources/cryptotoken/watchdog.js @@ -0,0 +1,95 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Provides a watchdog around a collection of callback functions. + */ +'use strict'; + +/** + * Creates a watchdog around a collection of callback functions, + * ensuring at least one of them is called before the timeout expires. + * If a timeout function is provided, calls the timeout function upon timeout + * expiration if none of the callback functions has been called. + * @param {number} timeoutValueSeconds Timeout value, in seconds. + * @param {function()=} opt_timeoutCb Callback function to call on timeout. + * @constructor + * @implements {Closeable} + */ +function WatchdogRequestHandler(timeoutValueSeconds, opt_timeoutCb) { + /** @private {number} */ + this.timeoutValueSeconds_ = timeoutValueSeconds; + /** @private {function()|undefined} */ + this.timeoutCb_ = opt_timeoutCb; + /** @private {boolean} */ + this.calledBack_ = false; + /** @private {Countdown} */ + this.timer_ = FACTORY_REGISTRY.getCountdownFactory().createTimer( + this.timeoutValueSeconds_ * 1000, this.timeout_.bind(this)); + /** @private {Closeable|undefined} */ + this.closeable_ = undefined; + /** @private {boolean} */ + this.closed_ = false; +} + +/** + * Wraps a callback function, such that the fact that the callback function + * was or was not called gets tracked by this watchdog object. + * @param {function(...?)} cb The callback function to wrap. + * @return {function(...?)} A wrapped callback function. + */ +WatchdogRequestHandler.prototype.wrapCallback = function(cb) { + return this.wrappedCallback_.bind(this, cb); +}; + +/** Closes this watchdog. */ +WatchdogRequestHandler.prototype.close = function() { + this.closed_ = true; + this.timer_.clearTimeout(); + if (this.closeable_) { + this.closeable_.close(); + this.closeable_ = undefined; + } +}; + +/** + * Sets this watchdog's closeable. + * @param {!Closeable} closeable The closeable. + */ +WatchdogRequestHandler.prototype.setCloseable = function(closeable) { + this.closeable_ = closeable; +}; + +/** + * Called back when the watchdog expires. + * @private + */ +WatchdogRequestHandler.prototype.timeout_ = function() { + if (!this.calledBack_ && !this.closed_) { + var logMsg = 'Not called back within ' + this.timeoutValueSeconds_ + + ' second timeout'; + if (this.timeoutCb_) { + logMsg += ', calling default callback'; + console.warn(UTIL_fmt(logMsg)); + this.timeoutCb_(); + } else { + console.warn(UTIL_fmt(logMsg)); + } + } +}; + +/** + * Wrapped callback function. + * @param {function(...?)} cb The callback function to call. + * @param {...?} var_args The callback function's arguments. + * @private + */ +WatchdogRequestHandler.prototype.wrappedCallback_ = function(cb, var_args) { + if (!this.closed_) { + this.calledBack_ = true; + this.timer_.clearTimeout(); + var originalArgs = Array.prototype.slice.call(arguments, 1); + cb.apply(null, originalArgs); + } +}; diff --git a/chrome/browser/resources/easy_unlock/manifest.json b/chrome/browser/resources/easy_unlock/manifest.json index 9c565406ca19a..b4e6a5929285a 100644 --- a/chrome/browser/resources/easy_unlock/manifest.json +++ b/chrome/browser/resources/easy_unlock/manifest.json @@ -1,6 +1,6 @@ { - "name": "Easy Unlock", - "description": "This app sets up unlocking the device with a phone.", + "name": "Smart Lock", + "description": "This app allows you to unlock your device when in proximity to your phone.", "version": "1.0", "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqOUeUl1nC6qTz6WwVUIaAJ4ukXVzgeCAumX4TZlCHFk5DLHImHLDBxakyVGaQFLS9iEQ3tDTsJLIoA+FkbWKNX7bvDW/qM89CeVNZsIZRGw898m8J78N6dJHwP9aZSI8CpoMK2KvjANpuj1tdWs1OM6v65zRUu6y4Mq876dr5AcPiuznGxl8jekagBwGu8jqMySsJxLazj/EfQ3W1E7mpyHd0Z4C1qNwJoFlUQeMjn6gfPZqa06BLU6YznzCUesiyjFK3d1vzbN54ZkVxhcA6ekwLKYLqKykBFLmIQG0gkNNePzcGXju8p34dGJgkcZw0sOXrtNaLSe1su0zfcniIwIDAQAB", diff --git a/chrome/browser/resources/gaia_auth/manifest.json b/chrome/browser/resources/gaia_auth/manifest.json index afc5e93b92d30..7295c01de7351 100644 --- a/chrome/browser/resources/gaia_auth/manifest.json +++ b/chrome/browser/resources/gaia_auth/manifest.json @@ -13,6 +13,7 @@ "" ], "js": ["channel.js", "saml_injected.js"], + "run_at": "document_start", "all_frames": true } ], diff --git a/chrome/browser/resources/gaia_auth/manifest_keyboard.json b/chrome/browser/resources/gaia_auth/manifest_keyboard.json index 99c03c44928b4..68d59a1f36eca 100644 --- a/chrome/browser/resources/gaia_auth/manifest_keyboard.json +++ b/chrome/browser/resources/gaia_auth/manifest_keyboard.json @@ -13,6 +13,7 @@ "" ], "js": ["channel.js", "saml_injected.js"], + "run_at": "document_start", "all_frames": true }, { diff --git a/chrome/browser/resources/plugin_metadata/plugins_chromeos.json b/chrome/browser/resources/plugin_metadata/plugins_chromeos.json index 5d3eed146c121..57e36857e75a4 100644 --- a/chrome/browser/resources/plugin_metadata/plugins_chromeos.json +++ b/chrome/browser/resources/plugin_metadata/plugins_chromeos.json @@ -1,12 +1,12 @@ { - "x-version": 1, + "x-version": 2, "google-talk": { "mime_types": [ ], "versions": [ { "version": "0", - "status": "up_to_date", + "status": "requires_authorization", "comment": "'Google Talk Plugin' and 'Google Talk Plugin Video Accelerator' are bundled with ChromeOS, so we don't define a minimum version." } ], diff --git a/chrome/browser/resources/plugin_metadata/plugins_linux.json b/chrome/browser/resources/plugin_metadata/plugins_linux.json index 367aff802c325..7ddd998578acb 100644 --- a/chrome/browser/resources/plugin_metadata/plugins_linux.json +++ b/chrome/browser/resources/plugin_metadata/plugins_linux.json @@ -1,12 +1,12 @@ { - "x-version": 4, + "x-version": 5, "google-talk": { "mime_types": [ ], "versions": [ { "version": "0", - "status": "up_to_date", + "status": "requires_authorization", "comment": "'Google Talk Plugin' and 'Google Talk Plugin Video Accelerator' use two completely different versioning schemes, so we can't define a minimum version." } ], diff --git a/chrome/browser/resources/plugin_metadata/plugins_mac.json b/chrome/browser/resources/plugin_metadata/plugins_mac.json index 40abf69ee85b8..cb424a9b4a7d7 100644 --- a/chrome/browser/resources/plugin_metadata/plugins_mac.json +++ b/chrome/browser/resources/plugin_metadata/plugins_mac.json @@ -1,12 +1,12 @@ { - "x-version": 5, + "x-version": 6, "google-talk": { "mime_types": [ ], "versions": [ { "version": "0", - "status": "up_to_date", + "status": "requires_authorization", "comment": "'Google Talk Plugin' and 'Google Talk Plugin Video Accelerator' use two completely different versioning schemes, so we can't define a minimum version." } ], @@ -260,7 +260,7 @@ "versions": [ { "version": "5.1.30214.0", - "status": "up_to_date", + "status": "requires_authorization", "reference": "https://support.microsoft.com/kb/2932677" } ], @@ -290,7 +290,7 @@ "versions": [ { "version": "0", - "status": "up_to_date", + "status": "requires_authorization", "comment": "We do not track version information for the Facebook Video Calling Plugin." } ], @@ -306,7 +306,7 @@ "versions": [ { "version": "0", - "status": "up_to_date", + "status": "requires_authorization", "comment": "We do not track version information for the Google Earth Plugin." } ], diff --git a/chrome/browser/resources/plugin_metadata/plugins_win.json b/chrome/browser/resources/plugin_metadata/plugins_win.json index 28853b4755f61..5d2229c0823e6 100644 --- a/chrome/browser/resources/plugin_metadata/plugins_win.json +++ b/chrome/browser/resources/plugin_metadata/plugins_win.json @@ -1,12 +1,12 @@ { - "x-version": 14, + "x-version": 15, "google-talk": { "mime_types": [ ], "versions": [ { "version": "0", - "status": "up_to_date", + "status": "requires_authorization", "comment": "'Google Talk Plugin' and 'Google Talk Plugin Video Accelerator' use two completely different versioning schemes, so we can't define a minimum version." } ], @@ -298,7 +298,7 @@ "versions": [ { "version": "5.1.30214.0", - "status": "up_to_date", + "status": "requires_authorization", "reference": "https://support.microsoft.com/kb/2932677" } ], @@ -366,7 +366,7 @@ "versions": [ { "version": "0", - "status": "up_to_date", + "status": "requires_authorization", "comment": "We do not track version information for the Facebook Video Calling Plugin." } ], @@ -382,7 +382,7 @@ "versions": [ { "version": "0", - "status": "up_to_date", + "status": "requires_authorization", "comment": "We do not track version information for the Google Earth Plugin." } ], diff --git a/chrome/browser/resources/print_preview/settings/dpi_settings.js b/chrome/browser/resources/print_preview/settings/dpi_settings.js index e39e9f41583ad..a06dc9e9df4e8 100644 --- a/chrome/browser/resources/print_preview/settings/dpi_settings.js +++ b/chrome/browser/resources/print_preview/settings/dpi_settings.js @@ -21,7 +21,11 @@ cr.define('print_preview', function() { /** @override */ getDefaultDisplayName_: function(option) { - return loadTimeData.getStringF('dpiItemLabel', option.horizontal_dpi); + var hDpi = option.horizontal_dpi || 0; + var vDpi = option.vertical_dpi || 0; + if (hDpi > 0 && vDpi > 0 && hDpi != vDpi) + return loadTimeData.getStringF('nonIsotropicDpiItemLabel', hDpi, vDpi); + return loadTimeData.getStringF('dpiItemLabel', hDpi || vDpi); } }; diff --git a/chrome/browser/safe_browsing/database_manager.cc b/chrome/browser/safe_browsing/database_manager.cc index 94b2c7613cc39..e0c634b682d84 100644 --- a/chrome/browser/safe_browsing/database_manager.cc +++ b/chrome/browser/safe_browsing/database_manager.cc @@ -67,26 +67,50 @@ bool IsExpectedThreat( threat_type); } -// Return the list id from the first result in |full_hashes| which matches +// Return the severest list id from the results in |full_hashes| which matches // |hash|, or INVALID if none match. -safe_browsing_util::ListType GetHashThreatListType( +safe_browsing_util::ListType GetHashSeverestThreatListType( const SBFullHash& hash, const std::vector& full_hashes, size_t* index) { + safe_browsing_util::ListType pending_threat = safe_browsing_util::INVALID; for (size_t i = 0; i < full_hashes.size(); ++i) { if (SBFullHashEqual(hash, full_hashes[i].hash)) { - if (index) - *index = i; - return static_cast(full_hashes[i].list_id); + const safe_browsing_util::ListType threat = + static_cast(full_hashes[i].list_id); + switch (threat) { + case safe_browsing_util::INVALID: + // |full_hashes| should never contain INVALID as a |list_id|. + NOTREACHED(); + break; + case safe_browsing_util::MALWARE: // Falls through. + case safe_browsing_util::PHISH: // Falls through. + case safe_browsing_util::BINURL: // Falls through. + case safe_browsing_util::CSDWHITELIST: // Falls through. + case safe_browsing_util::DOWNLOADWHITELIST: // Falls through. + case safe_browsing_util::EXTENSIONBLACKLIST: // Falls through. + case safe_browsing_util::SIDEEFFECTFREEWHITELIST: // Falls through. + case safe_browsing_util::IPBLACKLIST: + if (index) + *index = i; + return threat; + case safe_browsing_util::UNWANTEDURL: + // UNWANTEDURL is considered less severe than other threats, keep + // looking. + pending_threat = threat; + if (index) + *index = i; + break; + } } } - return safe_browsing_util::INVALID; + return pending_threat; } // Given a URL, compare all the possible host + path full hashes to the set of -// provided full hashes. Returns the list id of the a matching result from -// |full_hashes|, or INVALID if none match. -safe_browsing_util::ListType GetUrlThreatListType( +// provided full hashes. Returns the list id of the severest matching result +// from |full_hashes|, or INVALID if none match. +safe_browsing_util::ListType GetUrlSeverestThreatListType( const GURL& url, const std::vector& full_hashes, size_t* index) { @@ -96,13 +120,31 @@ safe_browsing_util::ListType GetUrlThreatListType( std::vector patterns; safe_browsing_util::GeneratePatternsToCheck(url, &patterns); + safe_browsing_util::ListType pending_threat = safe_browsing_util::INVALID; for (size_t i = 0; i < patterns.size(); ++i) { - safe_browsing_util::ListType threat = GetHashThreatListType( + safe_browsing_util::ListType threat = GetHashSeverestThreatListType( SBFullHashForString(patterns[i]), full_hashes, index); - if (threat != safe_browsing_util::INVALID) - return threat; + switch (threat) { + case safe_browsing_util::INVALID: + // Ignore patterns with no matching threat. + break; + case safe_browsing_util::MALWARE: // Falls through. + case safe_browsing_util::PHISH: // Falls through. + case safe_browsing_util::BINURL: // Falls through. + case safe_browsing_util::CSDWHITELIST: // Falls through. + case safe_browsing_util::DOWNLOADWHITELIST: // Falls through. + case safe_browsing_util::EXTENSIONBLACKLIST: // Falls through. + case safe_browsing_util::SIDEEFFECTFREEWHITELIST: // Falls through. + case safe_browsing_util::IPBLACKLIST: + return threat; + case safe_browsing_util::UNWANTEDURL: + // UNWANTEDURL is considered less severe than other threats, keep + // looking. + pending_threat = threat; + break; + } } - return safe_browsing_util::INVALID; + return pending_threat; } SBThreatType GetThreatTypeFromListType(safe_browsing_util::ListType list_type) { @@ -111,6 +153,8 @@ SBThreatType GetThreatTypeFromListType(safe_browsing_util::ListType list_type) { return SB_THREAT_TYPE_URL_PHISHING; case safe_browsing_util::MALWARE: return SB_THREAT_TYPE_URL_MALWARE; + case safe_browsing_util::UNWANTEDURL: + return SB_THREAT_TYPE_URL_UNWANTED; case safe_browsing_util::BINURL: return SB_THREAT_TYPE_BINARY_MALWARE_URL; case safe_browsing_util::EXTENSIONBLACKLIST: @@ -124,20 +168,20 @@ SBThreatType GetThreatTypeFromListType(safe_browsing_util::ListType list_type) { } // namespace // static -SBThreatType SafeBrowsingDatabaseManager::GetHashThreatType( +SBThreatType SafeBrowsingDatabaseManager::GetHashSeverestThreatType( const SBFullHash& hash, const std::vector& full_hashes) { return GetThreatTypeFromListType( - GetHashThreatListType(hash, full_hashes, NULL)); + GetHashSeverestThreatListType(hash, full_hashes, NULL)); } // static -SBThreatType SafeBrowsingDatabaseManager::GetUrlThreatType( +SBThreatType SafeBrowsingDatabaseManager::GetUrlSeverestThreatType( const GURL& url, const std::vector& full_hashes, size_t* index) { return GetThreatTypeFromListType( - GetUrlThreatListType(url, full_hashes, index)); + GetUrlSeverestThreatListType(url, full_hashes, index)); } SafeBrowsingDatabaseManager::SafeBrowsingCheck::SafeBrowsingCheck( @@ -170,6 +214,7 @@ void SafeBrowsingDatabaseManager::Client::OnSafeBrowsingResult( switch (check.check_type) { case safe_browsing_util::MALWARE: case safe_browsing_util::PHISH: + case safe_browsing_util::UNWANTEDURL: DCHECK_EQ(1u, check.urls.size()); OnCheckBrowseUrlResult( check.urls[0], check.url_results[0], check.url_metadata[0]); @@ -216,6 +261,7 @@ SafeBrowsingDatabaseManager::SafeBrowsingDatabaseManager( enable_extension_blacklist_(false), enable_side_effect_free_whitelist_(false), enable_ip_blacklist_(false), + enable_unwanted_software_blacklist_(false), update_in_progress_(false), database_update_in_progress_(false), closing_database_(false), @@ -252,6 +298,10 @@ SafeBrowsingDatabaseManager::SafeBrowsingDatabaseManager( // phishing protection for now. enable_ip_blacklist_ = enable_csd_whitelist_; + // TODO(gab): Gate this on the same experiment that will soon control the UwS + // URL UI. + enable_unwanted_software_blacklist_ = true; + enum SideEffectFreeWhitelistStatus { SIDE_EFFECT_FREE_WHITELIST_ENABLED, SIDE_EFFECT_FREE_WHITELIST_DISABLED, @@ -408,6 +458,7 @@ bool SafeBrowsingDatabaseManager::CheckBrowseUrl(const GURL& url, std::vector expected_threats; expected_threats.push_back(SB_THREAT_TYPE_URL_MALWARE); expected_threats.push_back(SB_THREAT_TYPE_URL_PHISHING); + expected_threats.push_back(SB_THREAT_TYPE_URL_UNWANTED); const base::TimeTicks start = base::TimeTicks::Now(); if (!MakeDatabaseAvailable()) { @@ -420,19 +471,45 @@ bool SafeBrowsingDatabaseManager::CheckBrowseUrl(const GURL& url, return false; } - std::vector prefix_hits; + // Cache hits should, in general, be the same for both (ignoring potential + // cache evictions in the second call for entries that were just about to be + // evicted in the first call). + // TODO(gab): Refactor SafeBrowsingDatabase to avoid depending on this here. std::vector cache_hits; - bool prefix_match = - database_->ContainsBrowseUrl(url, &prefix_hits, &cache_hits); + std::vector browse_prefix_hits; + bool browse_prefix_match = database_->ContainsBrowseUrl( + url, &browse_prefix_hits, &cache_hits); + + std::vector unwanted_prefix_hits; + std::vector unused_cache_hits; + bool unwanted_prefix_match = database_->ContainsUnwantedSoftwareUrl( + url, &unwanted_prefix_hits, &unused_cache_hits); + + // Merge the two pre-sorted prefix hits lists. + // TODO(gab): Refactor SafeBrowsingDatabase for it to return this merged list + // by default rather than building it here. + std::vector prefix_hits(browse_prefix_hits.size() + + unwanted_prefix_hits.size()); + std::merge(browse_prefix_hits.begin(), + browse_prefix_hits.end(), + unwanted_prefix_hits.begin(), + unwanted_prefix_hits.end(), + prefix_hits.begin()); + prefix_hits.erase(std::unique(prefix_hits.begin(), prefix_hits.end()), + prefix_hits.end()); UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::TimeTicks::Now() - start); - if (!prefix_match) + if (!browse_prefix_match && !unwanted_prefix_match) return true; // URL is okay. // Needs to be asynchronous, since we could be in the constructor of a // ResourceDispatcherHost event handler which can't pause there. + // This check will ping the Safe Browsing servers and get all lists which it + // matches. These lists will then be filtered against the |expected_threats| + // and the result callback for MALWARE (which is the same as for PHISH and + // UNWANTEDURL) will eventually be invoked with the final decision. SafeBrowsingCheck* check = new SafeBrowsingCheck(std::vector(1, url), std::vector(), client, @@ -704,7 +781,8 @@ SafeBrowsingDatabase* SafeBrowsingDatabaseManager::GetDatabase() { enable_download_whitelist_, enable_extension_blacklist_, enable_side_effect_free_whitelist_, - enable_ip_blacklist_); + enable_ip_blacklist_, + enable_unwanted_software_blacklist_); database->Init(SafeBrowsingService::GetBaseFilename()); { @@ -770,10 +848,7 @@ void SafeBrowsingDatabaseManager::OnCheckDone(SafeBrowsingCheck* check) { } else { // We may have cached results for previous GetHash queries. Since // this data comes from cache, don't histogram hits. - bool is_threat = HandleOneCheck(check, check->cache_hits); - // cache_hits should only contain hits for a fullhash we searched for, so if - // we got to this point it should always result in a threat match. - DCHECK(is_threat); + HandleOneCheck(check, check->cache_hits); } } @@ -939,21 +1014,26 @@ bool SafeBrowsingDatabaseManager::HandleOneCheck( bool is_threat = false; - // TODO(shess): GetHashThreadListType() contains a loop, - // GetUrlThreatListType() a loop around that loop. Having another loop out - // here concerns me. It is likely that SAFE is an expected outcome, which - // means all of those loops run to completion. Refactoring this to generate a - // set of sorted items to compare in sequence would probably improve things. + // TODO(shess): GetHashSeverestThreadListType() contains a loop, + // GetUrlSeverestThreatListType() a loop around that loop. Having another + // loop out here concerns me. It is likely that SAFE is an expected outcome, + // which means all of those loops run to completion. Refactoring this to + // generate a set of sorted items to compare in sequence would probably + // improve things. // // Additionally, the set of patterns generated from the urls is very similar // to the patterns generated in ContainsBrowseUrl() and other database checks, // which are called from this code. Refactoring that across the checks could // interact well with batching the checks here. + // TODO(gab): Fix the fact that Get(Url|Hash)SeverestThreatType() may return a + // threat for which IsExpectedThreat() returns false even if |full_hashes| + // actually contains an expected threat. + for (size_t i = 0; i < check->urls.size(); ++i) { size_t threat_index; SBThreatType threat = - GetUrlThreatType(check->urls[i], full_hashes, &threat_index); + GetUrlSeverestThreatType(check->urls[i], full_hashes, &threat_index); if (threat != SB_THREAT_TYPE_SAFE && IsExpectedThreat(threat, check->expected_threats)) { check->url_results[i] = threat; @@ -963,7 +1043,8 @@ bool SafeBrowsingDatabaseManager::HandleOneCheck( } for (size_t i = 0; i < check->full_hashes.size(); ++i) { - SBThreatType threat = GetHashThreatType(check->full_hashes[i], full_hashes); + SBThreatType threat = + GetHashSeverestThreatType(check->full_hashes[i], full_hashes); if (threat != SB_THREAT_TYPE_SAFE && IsExpectedThreat(threat, check->expected_threats)) { check->full_hash_results[i] = threat; diff --git a/chrome/browser/safe_browsing/database_manager.h b/chrome/browser/safe_browsing/database_manager.h index e001a35e07055..a3e011761e2f3 100644 --- a/chrome/browser/safe_browsing/database_manager.h +++ b/chrome/browser/safe_browsing/database_manager.h @@ -216,7 +216,8 @@ class SafeBrowsingDatabaseManager friend class SafeBrowsingServiceTest; friend class SafeBrowsingServiceTestHelper; friend class SafeBrowsingDatabaseManagerTest; - FRIEND_TEST_ALL_PREFIXES(SafeBrowsingDatabaseManagerTest, GetUrlThreatType); + FRIEND_TEST_ALL_PREFIXES(SafeBrowsingDatabaseManagerTest, + GetUrlSeverestThreatType); typedef std::set CurrentChecks; typedef std::vector GetHashRequestors; @@ -237,16 +238,16 @@ class SafeBrowsingDatabaseManager base::TimeTicks start; // When check was queued. }; - // Return the threat type from the first result in |full_hashes| which matches + // Return the threat type of the severest entry in |full_hashes| which matches // |hash|, or SAFE if none match. - static SBThreatType GetHashThreatType( + static SBThreatType GetHashSeverestThreatType( const SBFullHash& hash, const std::vector& full_hashes); // Given a URL, compare all the possible host + path full hashes to the set of - // provided full hashes. Returns the threat type of the matching result from - // |full_hashes|, or SAFE if none match. - static SBThreatType GetUrlThreatType( + // provided full hashes. Returns the threat type of the severest matching + // result from |full_hashes|, or SAFE if none match. + static SBThreatType GetUrlSeverestThreatType( const GURL& url, const std::vector& full_hashes, size_t* index); @@ -389,6 +390,9 @@ class SafeBrowsingDatabaseManager // Indicate if the csd malware IP blacklist should be enabled. bool enable_ip_blacklist_; + // Indicate if the unwanted software blacklist should be enabled. + bool enable_unwanted_software_blacklist_; + // The SafeBrowsing thread that runs database operations. // // Note: Functions that run on this thread should run synchronously and return diff --git a/chrome/browser/safe_browsing/database_manager_unittest.cc b/chrome/browser/safe_browsing/database_manager_unittest.cc index 915790f132e38..0c8c3a242db97 100644 --- a/chrome/browser/safe_browsing/database_manager_unittest.cc +++ b/chrome/browser/safe_browsing/database_manager_unittest.cc @@ -79,15 +79,21 @@ TEST_F(SafeBrowsingDatabaseManagerTest, CheckCorrespondsListType) { safe_browsing_util::kMalwareList)); } -TEST_F(SafeBrowsingDatabaseManagerTest, GetUrlThreatType) { +TEST_F(SafeBrowsingDatabaseManagerTest, GetUrlSeverestThreatType) { std::vector full_hashes; const GURL kMalwareUrl("http://www.malware.com/page.html"); const GURL kPhishingUrl("http://www.phishing.com/page.html"); + const GURL kUnwantedUrl("http://www.unwanted.com/page.html"); + const GURL kUnwantedAndMalwareUrl( + "http://www.unwantedandmalware.com/page.html"); const GURL kSafeUrl("http://www.safe.com/page.html"); const SBFullHash kMalwareHostHash = SBFullHashForString("malware.com/"); const SBFullHash kPhishingHostHash = SBFullHashForString("phishing.com/"); + const SBFullHash kUnwantedHostHash = SBFullHashForString("unwanted.com/"); + const SBFullHash kUnwantedAndMalwareHostHash = + SBFullHashForString("unwantedandmalware.com/"); const SBFullHash kSafeHostHash = SBFullHashForString("www.safe.com/"); { @@ -104,32 +110,73 @@ TEST_F(SafeBrowsingDatabaseManagerTest, GetUrlThreatType) { full_hashes.push_back(full_hash); } + { + SBFullHashResult full_hash; + full_hash.hash = kUnwantedHostHash; + full_hash.list_id = static_cast(safe_browsing_util::UNWANTEDURL); + full_hashes.push_back(full_hash); + } + + { + // Add both MALWARE and UNWANTEDURL list IDs for + // kUnwantedAndMalwareHostHash. + SBFullHashResult full_hash_malware; + full_hash_malware.hash = kUnwantedAndMalwareHostHash; + full_hash_malware.list_id = static_cast(safe_browsing_util::MALWARE); + full_hashes.push_back(full_hash_malware); + + SBFullHashResult full_hash_unwanted; + full_hash_unwanted.hash = kUnwantedAndMalwareHostHash; + full_hash_unwanted.list_id = + static_cast(safe_browsing_util::UNWANTEDURL); + full_hashes.push_back(full_hash_unwanted); + } + EXPECT_EQ(SB_THREAT_TYPE_URL_MALWARE, - SafeBrowsingDatabaseManager::GetHashThreatType( + SafeBrowsingDatabaseManager::GetHashSeverestThreatType( kMalwareHostHash, full_hashes)); EXPECT_EQ(SB_THREAT_TYPE_URL_PHISHING, - SafeBrowsingDatabaseManager::GetHashThreatType( + SafeBrowsingDatabaseManager::GetHashSeverestThreatType( kPhishingHostHash, full_hashes)); + EXPECT_EQ(SB_THREAT_TYPE_URL_UNWANTED, + SafeBrowsingDatabaseManager::GetHashSeverestThreatType( + kUnwantedHostHash, full_hashes)); + + EXPECT_EQ(SB_THREAT_TYPE_URL_MALWARE, + SafeBrowsingDatabaseManager::GetHashSeverestThreatType( + kUnwantedAndMalwareHostHash, full_hashes)); + EXPECT_EQ(SB_THREAT_TYPE_SAFE, - SafeBrowsingDatabaseManager::GetHashThreatType( + SafeBrowsingDatabaseManager::GetHashSeverestThreatType( kSafeHostHash, full_hashes)); - size_t index = 100; + const size_t kArbitraryValue = 123456U; + size_t index = kArbitraryValue; EXPECT_EQ(SB_THREAT_TYPE_URL_MALWARE, - SafeBrowsingDatabaseManager::GetUrlThreatType( + SafeBrowsingDatabaseManager::GetUrlSeverestThreatType( kMalwareUrl, full_hashes, &index)); EXPECT_EQ(0U, index); EXPECT_EQ(SB_THREAT_TYPE_URL_PHISHING, - SafeBrowsingDatabaseManager::GetUrlThreatType( + SafeBrowsingDatabaseManager::GetUrlSeverestThreatType( kPhishingUrl, full_hashes, &index)); EXPECT_EQ(1U, index); - index = 100; + EXPECT_EQ(SB_THREAT_TYPE_URL_UNWANTED, + SafeBrowsingDatabaseManager::GetUrlSeverestThreatType( + kUnwantedUrl, full_hashes, &index)); + EXPECT_EQ(2U, index); + + EXPECT_EQ(SB_THREAT_TYPE_URL_MALWARE, + SafeBrowsingDatabaseManager::GetUrlSeverestThreatType( + kUnwantedAndMalwareUrl, full_hashes, &index)); + EXPECT_EQ(3U, index); + + index = kArbitraryValue; EXPECT_EQ(SB_THREAT_TYPE_SAFE, - SafeBrowsingDatabaseManager::GetUrlThreatType( + SafeBrowsingDatabaseManager::GetUrlSeverestThreatType( kSafeUrl, full_hashes, &index)); - EXPECT_EQ(100U, index); + EXPECT_EQ(kArbitraryValue, index); } diff --git a/chrome/browser/safe_browsing/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection_service.cc index ba255be92d30f..30f2523adcc4a 100644 --- a/chrome/browser/safe_browsing/download_protection_service.cc +++ b/chrome/browser/safe_browsing/download_protection_service.cc @@ -644,6 +644,9 @@ class DownloadProtectionService::CheckClientDownloadRequest void GetTabRedirects() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (!service_) + return; + if (!tab_url_.is_valid()) { SendRequest(); return; @@ -669,6 +672,8 @@ class DownloadProtectionService::CheckClientDownloadRequest const history::RedirectList* redirect_list) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK_EQ(url, tab_url_); + if (!service_) + return; if (!redirect_list->empty()) { tab_redirects_.insert( diff --git a/chrome/browser/safe_browsing/download_protection_service_unittest.cc b/chrome/browser/safe_browsing/download_protection_service_unittest.cc index b06e8c8e7fb46..84fd01d55bd24 100644 --- a/chrome/browser/safe_browsing/download_protection_service_unittest.cc +++ b/chrome/browser/safe_browsing/download_protection_service_unittest.cc @@ -50,6 +50,7 @@ using ::testing::Assign; using ::testing::ContainerEq; using ::testing::DoAll; using ::testing::ElementsAre; +using ::testing::Invoke; using ::testing::Mock; using ::testing::NotNull; using ::testing::Return; @@ -1599,6 +1600,7 @@ TEST_F(DownloadProtectionServiceTest, TestDownloadItemDestroyed) { std::vector url_chain; url_chain.push_back(GURL("http://www.evil.com/bla.exe")); GURL referrer("http://www.google.com/"); + GURL tab_url("http://www.google.com/tab"); base::FilePath tmp_path(FILE_PATH_LITERAL("a.tmp")); base::FilePath final_path(FILE_PATH_LITERAL("a.exe")); std::string hash = "hash"; @@ -1610,7 +1612,7 @@ TEST_F(DownloadProtectionServiceTest, TestDownloadItemDestroyed) { .WillRepeatedly(ReturnRef(final_path)); EXPECT_CALL(item, GetUrlChain()).WillRepeatedly(ReturnRef(url_chain)); EXPECT_CALL(item, GetReferrerUrl()).WillRepeatedly(ReturnRef(referrer)); - EXPECT_CALL(item, GetTabUrl()).WillRepeatedly(ReturnRef(GURL::EmptyGURL())); + EXPECT_CALL(item, GetTabUrl()).WillRepeatedly(ReturnRef(tab_url)); EXPECT_CALL(item, GetTabReferrerUrl()) .WillRepeatedly(ReturnRef(GURL::EmptyGURL())); EXPECT_CALL(item, GetHash()).WillRepeatedly(ReturnRef(hash)); @@ -1637,6 +1639,52 @@ TEST_F(DownloadProtectionServiceTest, TestDownloadItemDestroyed) { EXPECT_FALSE(HasClientDownloadRequest()); } +TEST_F(DownloadProtectionServiceTest, + TestDownloadItemDestroyedDuringWhitelistCheck) { + net::TestURLFetcherFactory factory; + + std::vector url_chain; + url_chain.push_back(GURL("http://www.evil.com/bla.exe")); + GURL referrer("http://www.google.com/"); + GURL tab_url("http://www.google.com/tab"); + base::FilePath tmp_path(FILE_PATH_LITERAL("a.tmp")); + base::FilePath final_path(FILE_PATH_LITERAL("a.exe")); + std::string hash = "hash"; + + scoped_ptr item(new content::MockDownloadItem); + EXPECT_CALL(*item, GetFullPath()).WillRepeatedly(ReturnRef(tmp_path)); + EXPECT_CALL(*item, GetTargetFilePath()) + .WillRepeatedly(ReturnRef(final_path)); + EXPECT_CALL(*item, GetUrlChain()).WillRepeatedly(ReturnRef(url_chain)); + EXPECT_CALL(*item, GetReferrerUrl()).WillRepeatedly(ReturnRef(referrer)); + EXPECT_CALL(*item, GetTabUrl()).WillRepeatedly(ReturnRef(tab_url)); + EXPECT_CALL(*item, GetTabReferrerUrl()) + .WillRepeatedly(ReturnRef(GURL::EmptyGURL())); + EXPECT_CALL(*item, GetHash()).WillRepeatedly(ReturnRef(hash)); + EXPECT_CALL(*item, GetReceivedBytes()).WillRepeatedly(Return(100)); + EXPECT_CALL(*item, HasUserGesture()).WillRepeatedly(Return(true)); + EXPECT_CALL(*item, GetRemoteAddress()).WillRepeatedly(Return("")); + + EXPECT_CALL(*sb_service_->mock_database_manager(), + MatchDownloadWhitelistUrl(_)) + .WillRepeatedly(Invoke([&item](const GURL&) { + item.reset(); + return false; + })); + EXPECT_CALL(*binary_feature_extractor_.get(), CheckSignature(tmp_path, _)); + EXPECT_CALL(*binary_feature_extractor_.get(), + ExtractImageHeaders(tmp_path, _)); + + download_service_->CheckClientDownload( + item.get(), + base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback, + base::Unretained(this))); + + MessageLoop::current()->Run(); + EXPECT_TRUE(IsResult(DownloadProtectionService::UNKNOWN)); + EXPECT_FALSE(HasClientDownloadRequest()); +} + TEST_F(DownloadProtectionServiceTest, GetCertificateWhitelistStrings) { // We'll pass this cert in as the "issuer", even though it isn't really // used to sign the certs below. GetCertificateWhitelistStirngs doesn't care diff --git a/chrome/browser/safe_browsing/incident_reporting/download_metadata_manager.cc b/chrome/browser/safe_browsing/incident_reporting/download_metadata_manager.cc index c4b184f0797d3..6a6acd0a75845 100644 --- a/chrome/browser/safe_browsing/incident_reporting/download_metadata_manager.cc +++ b/chrome/browser/safe_browsing/incident_reporting/download_metadata_manager.cc @@ -453,6 +453,11 @@ void DownloadMetadataManager::ManagerContext::RemoveMetadata() { } // Remove any metadata. download_metadata_.reset(); + // Stop observing this item. + if (item_) { + item_->RemoveObserver(this); + item_= nullptr; + } write_runner_->PostTask( FROM_HERE, base::Bind(&DeleteMetadataOnWorkerPool, metadata_path_)); // Run callbacks (only present in case of a transition to LOAD_COMPLETE). diff --git a/chrome/browser/safe_browsing/incident_reporting/download_metadata_manager_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/download_metadata_manager_unittest.cc index 071ec3c591ee2..538a7dacf6b6a 100644 --- a/chrome/browser/safe_browsing/incident_reporting/download_metadata_manager_unittest.cc +++ b/chrome/browser/safe_browsing/incident_reporting/download_metadata_manager_unittest.cc @@ -485,4 +485,28 @@ INSTANTIATE_TEST_CASE_P( testing::Values("waiting", "loaded"), testing::Values("clear", "set"))); +class DownloadMetadataManagerTest : public DownloadMetadataManagerTestBase { + protected: +}; + +// Test that that opening an item when there is no corresponding metadata works. +TEST_F(DownloadMetadataManagerTest, OpenDownloadNoMetadata) { + // Add a download manager and some items. + WriteTestMetadataFile(); + AddDownloadManager(); + AddDownloadItems(); + + // Allow the metadata manager to discover that no metadata is available. + RunAllTasks(); + + // Clear metadata. + manager_.SetRequest(test_item_.get(), nullptr); + + // Open an item. + test_item_->NotifyObserversDownloadOpened(); + + // Shut down. + ShutdownDownloadManager(); +} + } // namespace safe_browsing diff --git a/chrome/browser/safe_browsing/ping_manager.cc b/chrome/browser/safe_browsing/ping_manager.cc index 92b032921beee..04783410fcef1 100644 --- a/chrome/browser/safe_browsing/ping_manager.cc +++ b/chrome/browser/safe_browsing/ping_manager.cc @@ -101,6 +101,7 @@ GURL SafeBrowsingPingManager::SafeBrowsingHitUrl( SBThreatType threat_type) const { DCHECK(threat_type == SB_THREAT_TYPE_URL_MALWARE || threat_type == SB_THREAT_TYPE_URL_PHISHING || + threat_type == SB_THREAT_TYPE_URL_UNWANTED || threat_type == SB_THREAT_TYPE_BINARY_MALWARE_URL || threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL || threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL); @@ -114,6 +115,9 @@ GURL SafeBrowsingPingManager::SafeBrowsingHitUrl( case SB_THREAT_TYPE_URL_PHISHING: threat_list = "phishblhit"; break; + case SB_THREAT_TYPE_URL_UNWANTED: + threat_list = "uwsblhit"; + break; case SB_THREAT_TYPE_BINARY_MALWARE_URL: threat_list = "binurlhit"; break; diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc index 1c47c2c4c84b4..9c3ca1ef2483d 100644 --- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc +++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc @@ -173,7 +173,7 @@ SafeBrowsingBlockingPage::SafeBrowsingBlockingPage( if (threat_type == SB_THREAT_TYPE_URL_MALWARE || threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL) { malware = true; - } else if (threat_type == SB_THREAT_TYPE_URL_HARMFUL) { + } else if (threat_type == SB_THREAT_TYPE_URL_UNWANTED) { harmful = true; } else { DCHECK(threat_type == SB_THREAT_TYPE_URL_PHISHING || @@ -378,9 +378,11 @@ void SafeBrowsingBlockingPage::CommandReceived(const std::string& cmd) { diagnostic_url = google_util::AppendGoogleLocaleParam( diagnostic_url, g_browser_process->GetApplicationLocale()); DCHECK(unsafe_resources_[element_index].threat_type == - SB_THREAT_TYPE_URL_MALWARE || + SB_THREAT_TYPE_URL_MALWARE || unsafe_resources_[element_index].threat_type == - SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL); + SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL || + unsafe_resources_[element_index].threat_type == + SB_THREAT_TYPE_URL_UNWANTED); OpenURLParams params( diagnostic_url, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_LINK, false); diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc index 07c02654993f9..42d0d694d335c 100644 --- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc +++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc @@ -634,7 +634,7 @@ IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageBrowserTest, return; #endif - SetupWarningAndNavigate(SB_THREAT_TYPE_URL_HARMFUL); + SetupWarningAndNavigate(SB_THREAT_TYPE_URL_UNWANTED); EXPECT_EQ(VISIBLE, GetVisibility("primary-button")); EXPECT_EQ(HIDDEN, GetVisibility("details")); @@ -661,7 +661,7 @@ IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageBrowserTest, MalwareProceed) { } IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageBrowserTest, HarmfulProceed) { - GURL url = SetupWarningAndNavigate(SB_THREAT_TYPE_URL_HARMFUL); + GURL url = SetupWarningAndNavigate(SB_THREAT_TYPE_URL_UNWANTED); EXPECT_TRUE(ClickAndWaitForDetach("proceed-link")); AssertNoInterstitial(true); // Assert the interstitial is gone. diff --git a/chrome/browser/safe_browsing/safe_browsing_database.cc b/chrome/browser/safe_browsing/safe_browsing_database.cc index dea4b3caef248..11b16f304bfa4 100644 --- a/chrome/browser/safe_browsing/safe_browsing_database.cc +++ b/chrome/browser/safe_browsing/safe_browsing_database.cc @@ -57,6 +57,9 @@ const base::FilePath::CharType kSideEffectFreeWhitelistDBFile[] = // Filename suffix for the csd malware IP blacklist store. const base::FilePath::CharType kIPBlacklistDBFile[] = FILE_PATH_LITERAL(" IP Blacklist"); +// Filename suffix for the unwanted software blacklist store. +const base::FilePath::CharType kUnwantedSoftwareDBFile[] = + FILE_PATH_LITERAL(" UwS List"); // Filename suffix for browse store. // TODO(shess): "Safe Browsing Bloom Prefix Set" is full of win. @@ -122,9 +125,9 @@ int EncodeChunkId(const int chunk, const int list_id) { // does an early exit on match. Since match should be the infrequent // case (phishing or malware found), consider combining this function // with that one. -void BrowseFullHashesToCheck(const GURL& url, - bool include_whitelist_hashes, - std::vector* full_hashes) { +void UrlToFullHashes(const GURL& url, + bool include_whitelist_hashes, + std::vector* full_hashes) { std::vector hosts; if (url.HostIsIPAddress()) { hosts.push_back(url.host()); @@ -158,7 +161,7 @@ void GetDownloadUrlPrefixes(const std::vector& urls, std::vector* prefixes) { std::vector full_hashes; for (size_t i = 0; i < urls.size(); ++i) - BrowseFullHashesToCheck(urls[i], false, &full_hashes); + UrlToFullHashes(urls[i], false, &full_hashes); for (size_t i = 0; i < full_hashes.size(); ++i) prefixes->push_back(full_hashes[i].prefix); @@ -277,7 +280,7 @@ int64 GetFileSizeOrZero(const base::FilePath& file_path) { return size_64; } -// Helper for ContainsBrowseUrlHashes(). Returns true if an un-expired match +// Helper for PrefixSetContainsUrlHashes(). Returns true if an un-expired match // for |full_hash| is found in |cache|, with any matches appended to |results| // (true can be returned with zero matches). |expire_base| is used to check the // cache lifetime of matches, expired matches will be discarded from |cache|. @@ -319,7 +322,8 @@ class SafeBrowsingDatabaseFactoryImpl : public SafeBrowsingDatabaseFactory { bool enable_download_whitelist, bool enable_extension_blacklist, bool enable_side_effect_free_whitelist, - bool enable_ip_blacklist) override { + bool enable_ip_blacklist, + bool enable_unwanted_software_list) override { return new SafeBrowsingDatabaseNew( new SafeBrowsingStoreFile, enable_download_protection ? new SafeBrowsingStoreFile : NULL, @@ -327,7 +331,8 @@ class SafeBrowsingDatabaseFactoryImpl : public SafeBrowsingDatabaseFactory { enable_download_whitelist ? new SafeBrowsingStoreFile : NULL, enable_extension_blacklist ? new SafeBrowsingStoreFile : NULL, enable_side_effect_free_whitelist ? new SafeBrowsingStoreFile : NULL, - enable_ip_blacklist ? new SafeBrowsingStoreFile : NULL); + enable_ip_blacklist ? new SafeBrowsingStoreFile : NULL, + enable_unwanted_software_list ? new SafeBrowsingStoreFile : NULL); } SafeBrowsingDatabaseFactoryImpl() { } @@ -350,16 +355,17 @@ SafeBrowsingDatabase* SafeBrowsingDatabase::Create( bool enable_download_whitelist, bool enable_extension_blacklist, bool enable_side_effect_free_whitelist, - bool enable_ip_blacklist) { + bool enable_ip_blacklist, + bool enable_unwanted_software_list) { if (!factory_) factory_ = new SafeBrowsingDatabaseFactoryImpl(); - return factory_->CreateSafeBrowsingDatabase( - enable_download_protection, - enable_client_side_whitelist, - enable_download_whitelist, - enable_extension_blacklist, - enable_side_effect_free_whitelist, - enable_ip_blacklist); + return factory_->CreateSafeBrowsingDatabase(enable_download_protection, + enable_client_side_whitelist, + enable_download_whitelist, + enable_extension_blacklist, + enable_side_effect_free_whitelist, + enable_ip_blacklist, + enable_unwanted_software_list); } SafeBrowsingDatabase::~SafeBrowsingDatabase() { @@ -419,6 +425,12 @@ base::FilePath SafeBrowsingDatabase::IpBlacklistDBFilename( return base::FilePath(db_filename.value() + kIPBlacklistDBFile); } +// static +base::FilePath SafeBrowsingDatabase::UnwantedSoftwareDBFilename( + const base::FilePath& db_filename) { + return base::FilePath(db_filename.value() + kUnwantedSoftwareDBFile); +} + SafeBrowsingStore* SafeBrowsingDatabaseNew::GetStore(const int list_id) { if (list_id == safe_browsing_util::PHISH || list_id == safe_browsing_util::MALWARE) { @@ -435,6 +447,8 @@ SafeBrowsingStore* SafeBrowsingDatabaseNew::GetStore(const int list_id) { return side_effect_free_whitelist_store_.get(); } else if (list_id == safe_browsing_util::IPBLACKLIST) { return ip_blacklist_store_.get(); + } else if (list_id == safe_browsing_util::UNWANTEDURL) { + return unwanted_software_store_.get(); } return NULL; } @@ -458,6 +472,7 @@ SafeBrowsingDatabaseNew::SafeBrowsingDatabaseNew() DCHECK(!extension_blacklist_store_.get()); DCHECK(!side_effect_free_whitelist_store_.get()); DCHECK(!ip_blacklist_store_.get()); + DCHECK(!unwanted_software_store_.get()); } SafeBrowsingDatabaseNew::SafeBrowsingDatabaseNew( @@ -467,7 +482,8 @@ SafeBrowsingDatabaseNew::SafeBrowsingDatabaseNew( SafeBrowsingStore* download_whitelist_store, SafeBrowsingStore* extension_blacklist_store, SafeBrowsingStore* side_effect_free_whitelist_store, - SafeBrowsingStore* ip_blacklist_store) + SafeBrowsingStore* ip_blacklist_store, + SafeBrowsingStore* unwanted_software_store) : creation_loop_(base::MessageLoop::current()), browse_store_(browse_store), download_store_(download_store), @@ -476,6 +492,7 @@ SafeBrowsingDatabaseNew::SafeBrowsingDatabaseNew( extension_blacklist_store_(extension_blacklist_store), side_effect_free_whitelist_store_(side_effect_free_whitelist_store), ip_blacklist_store_(ip_blacklist_store), + unwanted_software_store_(unwanted_software_store), corruption_detected_(false), reset_factory_(this) { DCHECK(browse_store_.get()); @@ -495,7 +512,8 @@ void SafeBrowsingDatabaseNew::Init(const base::FilePath& filename_base) { filename_base_ = filename_base; // TODO(shess): The various stores are really only necessary while doing - // updates, or when querying a store directly (see |ContainsDownloadUrl()|). + // updates (see |UpdateFinished()|) or when querying a store directly (see + // |ContainsDownloadUrl()|). // The store variables are also tested to see if a list is enabled. Perhaps // the stores could be refactored into an update object so that they are only // live in memory while being actively used. The sense of enabled probably @@ -506,14 +524,28 @@ void SafeBrowsingDatabaseNew::Init(const base::FilePath& filename_base) { base::Bind(&SafeBrowsingDatabaseNew::HandleCorruptDatabase, base::Unretained(this))); + if (unwanted_software_store_.get()) { + unwanted_software_store_->Init( + UnwantedSoftwareDBFilename(filename_base_), + base::Bind(&SafeBrowsingDatabaseNew::HandleCorruptDatabase, + base::Unretained(this))); + } + { // NOTE: There is no need to grab the lock in this function, since // until it returns, there are no pointers to this class on other // threads. Then again, that means there is no possibility of // contention on the lock... base::AutoLock locked(lookup_lock_); - browse_gethash_cache_.clear(); - LoadPrefixSet(); + prefix_gethash_cache_.clear(); + LoadPrefixSet(BrowseDBFilename(filename_base_), + &browse_prefix_set_, + FAILURE_BROWSE_PREFIX_SET_READ); + if (unwanted_software_store_.get()) { + LoadPrefixSet(UnwantedSoftwareDBFilename(filename_base_), + &unwanted_software_prefix_set_, + FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_READ); + } } if (download_store_.get()) { @@ -620,10 +652,11 @@ bool SafeBrowsingDatabaseNew::ResetDatabase() { // Reset objects in memory. { base::AutoLock locked(lookup_lock_); - browse_gethash_cache_.clear(); + prefix_gethash_cache_.clear(); browse_prefix_set_.reset(); side_effect_free_whitelist_prefix_set_.reset(); ip_blacklist_.clear(); + unwanted_software_prefix_set_.reset(); } // Wants to acquire the lock itself. WhitelistEverything(&csd_whitelist_); @@ -635,20 +668,47 @@ bool SafeBrowsingDatabaseNew::ContainsBrowseUrl( const GURL& url, std::vector* prefix_hits, std::vector* cache_hits) { + return PrefixSetContainsUrl( + url, &browse_prefix_set_, prefix_hits, cache_hits); +} + +bool SafeBrowsingDatabaseNew::ContainsUnwantedSoftwareUrl( + const GURL& url, + std::vector* prefix_hits, + std::vector* cache_hits) { + return PrefixSetContainsUrl( + url, &unwanted_software_prefix_set_, prefix_hits, cache_hits); +} + +bool SafeBrowsingDatabaseNew::PrefixSetContainsUrl( + const GURL& url, + scoped_ptr* prefix_set_getter, + std::vector* prefix_hits, + std::vector* cache_hits) { // Clear the results first. prefix_hits->clear(); cache_hits->clear(); std::vector full_hashes; - BrowseFullHashesToCheck(url, false, &full_hashes); + UrlToFullHashes(url, false, &full_hashes); if (full_hashes.empty()) return false; - return ContainsBrowseUrlHashes(full_hashes, prefix_hits, cache_hits); + return PrefixSetContainsUrlHashes( + full_hashes, prefix_set_getter, prefix_hits, cache_hits); +} + +bool SafeBrowsingDatabaseNew::ContainsBrowseUrlHashesForTesting( + const std::vector& full_hashes, + std::vector* prefix_hits, + std::vector* cache_hits) { + return PrefixSetContainsUrlHashes( + full_hashes, &browse_prefix_set_, prefix_hits, cache_hits); } -bool SafeBrowsingDatabaseNew::ContainsBrowseUrlHashes( +bool SafeBrowsingDatabaseNew::PrefixSetContainsUrlHashes( const std::vector& full_hashes, + scoped_ptr* prefix_set_getter, std::vector* prefix_hits, std::vector* cache_hits) { // Used to determine cache expiration. @@ -658,19 +718,20 @@ bool SafeBrowsingDatabaseNew::ContainsBrowseUrlHashes( // filter and caches. base::AutoLock locked(lookup_lock_); - // |browse_prefix_set_| is empty until it is either read from disk, or the - // first update populates it. Bail out without a hit if not yet - // available. - if (!browse_prefix_set_.get()) + // |prefix_set| is empty until it is either read from disk, or the first + // update populates it. Bail out without a hit if not yet available. + // |prefix_set_getter| can only be accessed while holding |lookup_lock_| hence + // why it is passed as a parameter rather than passing the |prefix_set| + // directly. + safe_browsing::PrefixSet* prefix_set = prefix_set_getter->get(); + if (!prefix_set) return false; for (size_t i = 0; i < full_hashes.size(); ++i) { - if (!GetCachedFullHash(&browse_gethash_cache_, - full_hashes[i], - now, - cache_hits)) { + if (!GetCachedFullHash( + &prefix_gethash_cache_, full_hashes[i], now, cache_hits)) { // No valid cached result, check the database. - if (browse_prefix_set_->Exists(full_hashes[i])) + if (prefix_set->Exists(full_hashes[i])) prefix_hits->push_back(full_hashes[i].prefix); } } @@ -705,13 +766,13 @@ bool SafeBrowsingDatabaseNew::ContainsCsdWhitelistedUrl(const GURL& url) { // originate from the IO thread. DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); std::vector full_hashes; - BrowseFullHashesToCheck(url, true, &full_hashes); + UrlToFullHashes(url, true, &full_hashes); return ContainsWhitelistedHashes(csd_whitelist_, full_hashes); } bool SafeBrowsingDatabaseNew::ContainsDownloadWhitelistedUrl(const GURL& url) { std::vector full_hashes; - BrowseFullHashesToCheck(url, true, &full_hashes); + UrlToFullHashes(url, true, &full_hashes); return ContainsWhitelistedHashes(download_whitelist_, full_hashes); } @@ -951,14 +1012,14 @@ void SafeBrowsingDatabaseNew::CacheHashResults( // Create or reset all cached results for these prefixes. for (size_t i = 0; i < prefixes.size(); ++i) { - browse_gethash_cache_[prefixes[i]] = SBCachedFullHashResult(expire_after); + prefix_gethash_cache_[prefixes[i]] = SBCachedFullHashResult(expire_after); } // Insert any fullhash hits. Note that there may be one, multiple, or no // fullhashes for any given entry in |prefixes|. for (size_t i = 0; i < full_hits.size(); ++i) { const SBPrefix prefix = full_hits[i].hash.prefix; - browse_gethash_cache_[prefix].full_hashes.push_back(full_hits[i]); + prefix_gethash_cache_[prefix].full_hashes.push_back(full_hits[i]); } } @@ -1013,11 +1074,17 @@ bool SafeBrowsingDatabaseNew::UpdateStarted( return false; } + if (unwanted_software_store_ && !unwanted_software_store_->BeginUpdate()) { + RecordFailure(FAILURE_UNWANTED_SOFTWARE_DATABASE_UPDATE_BEGIN); + HandleCorruptDatabase(); + return false; + } + { base::AutoLock locked(lookup_lock_); // Cached fullhash results must be cleared on every database update (whether // successful or not.) - browse_gethash_cache_.clear(); + prefix_gethash_cache_.clear(); } UpdateChunkRangesForLists(browse_store_.get(), @@ -1047,6 +1114,10 @@ bool SafeBrowsingDatabaseNew::UpdateStarted( UpdateChunkRangesForList(ip_blacklist_store_.get(), safe_browsing_util::kIPBlacklist, lists); + UpdateChunkRangesForList(unwanted_software_store_.get(), + safe_browsing_util::kUnwantedUrlList, + lists); + corruption_detected_ = false; change_detected_ = false; return true; @@ -1090,6 +1161,11 @@ void SafeBrowsingDatabaseNew::UpdateFinished(bool update_succeeded) { if (ip_blacklist_store_ && !ip_blacklist_store_->CheckValidity()) { DLOG(ERROR) << "Safe-browsing IP blacklist database corrupt."; } + + if (unwanted_software_store_ && + !unwanted_software_store_->CheckValidity()) { + DLOG(ERROR) << "Unwanted software url list database corrupt."; + } } if (corruption_detected_) @@ -1115,6 +1191,8 @@ void SafeBrowsingDatabaseNew::UpdateFinished(bool update_succeeded) { side_effect_free_whitelist_store_->CancelUpdate(); if (ip_blacklist_store_) ip_blacklist_store_->CancelUpdate(); + if (unwanted_software_store_) + unwanted_software_store_->CancelUpdate(); return; } @@ -1127,7 +1205,12 @@ void SafeBrowsingDatabaseNew::UpdateFinished(bool update_succeeded) { static_cast(size_bytes / 1024)); } - UpdateBrowseStore(); + UpdatePrefixSetUrlStore(BrowseDBFilename(filename_base_), + browse_store_.get(), + &browse_prefix_set_, + FAILURE_BROWSE_DATABASE_UPDATE_FINISH, + FAILURE_BROWSE_PREFIX_SET_WRITE); + UpdateWhitelistStore(CsdWhitelistDBFilename(filename_base_), csd_whitelist_store_.get(), &csd_whitelist_); @@ -1149,6 +1232,14 @@ void SafeBrowsingDatabaseNew::UpdateFinished(bool update_succeeded) { if (ip_blacklist_store_) UpdateIpBlacklistStore(); + + if (unwanted_software_store_) { + UpdatePrefixSetUrlStore(UnwantedSoftwareDBFilename(filename_base_), + unwanted_software_store_.get(), + &unwanted_software_prefix_set_, + FAILURE_UNWANTED_SOFTWARE_DATABASE_UPDATE_FINISH, + FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_WRITE); + } } void SafeBrowsingDatabaseNew::UpdateWhitelistStore( @@ -1194,7 +1285,12 @@ int64 SafeBrowsingDatabaseNew::UpdateHashPrefixStore( return GetFileSizeOrZero(store_filename); } -void SafeBrowsingDatabaseNew::UpdateBrowseStore() { +void SafeBrowsingDatabaseNew::UpdatePrefixSetUrlStore( + const base::FilePath& db_filename, + SafeBrowsingStore* url_store, + scoped_ptr* prefix_set, + FailureType finish_failure_type, + FailureType write_failure_type) { // Measure the amount of IO during the filter build. base::IoCounters io_before, io_after; base::ProcessHandle handle = base::GetCurrentProcessHandle(); @@ -1219,8 +1315,8 @@ void SafeBrowsingDatabaseNew::UpdateBrowseStore() { // the SBFullHash portion. It would need an accessor on PrefixSet. safe_browsing::PrefixSetBuilder builder; std::vector add_full_hashes; - if (!browse_store_->FinishUpdate(&builder, &add_full_hashes)) { - RecordFailure(FAILURE_BROWSE_DATABASE_UPDATE_FINISH); + if (!url_store->FinishUpdate(&builder, &add_full_hashes)) { + RecordFailure(finish_failure_type); return; } @@ -1229,20 +1325,22 @@ void SafeBrowsingDatabaseNew::UpdateBrowseStore() { full_hash_results.push_back(add_full_hashes[i].full_hash); } - scoped_ptr - prefix_set(builder.GetPrefixSet(full_hash_results)); + scoped_ptr new_prefix_set( + builder.GetPrefixSet(full_hash_results)); // Swap in the newly built filter. { base::AutoLock locked(lookup_lock_); - browse_prefix_set_.swap(prefix_set); + prefix_set->swap(new_prefix_set); } UMA_HISTOGRAM_LONG_TIMES("SB2.BuildFilter", base::TimeTicks::Now() - before); - // Persist the prefix set to disk. Since only this thread changes - // |browse_prefix_set_|, there is no need to lock. - WritePrefixSet(); + // Persist the prefix set to disk. Note: there is no need to lock since the + // only write to |*prefix_set| is on this thread (in the swap() above). + // TODO(gab): Strengthen this requirement by design (const pointers) rather + // than assumptions. + WritePrefixSet(db_filename, prefix_set->get(), write_failure_type); // Gather statistics. if (got_counters && metric->GetIOCounters(&io_after)) { @@ -1260,13 +1358,12 @@ void SafeBrowsingDatabaseNew::UpdateBrowseStore() { io_before.WriteOperationCount)); } - const base::FilePath browse_filename = BrowseDBFilename(filename_base_); - const int64 file_size = GetFileSizeOrZero(browse_filename); + const int64 file_size = GetFileSizeOrZero(db_filename); UMA_HISTOGRAM_COUNTS("SB2.BrowseDatabaseKilobytes", static_cast(file_size / 1024)); #if defined(OS_MACOSX) - base::mac::SetFileBackupExclusion(browse_filename); + base::mac::SetFileBackupExclusion(db_filename); #endif } @@ -1360,31 +1457,34 @@ void SafeBrowsingDatabaseNew::OnHandleCorruptDatabase() { // TODO(shess): I'm not clear why this code doesn't have any // real error-handling. -void SafeBrowsingDatabaseNew::LoadPrefixSet() { +void SafeBrowsingDatabaseNew::LoadPrefixSet( + const base::FilePath& db_filename, + scoped_ptr* prefix_set, + FailureType read_failure_type) { + if (!prefix_set) + return; + DCHECK_EQ(creation_loop_, base::MessageLoop::current()); DCHECK(!filename_base_.empty()); - const base::FilePath browse_filename = BrowseDBFilename(filename_base_); - const base::FilePath browse_prefix_set_filename = - PrefixSetForFilename(browse_filename); + const base::FilePath prefix_set_filename = PrefixSetForFilename(db_filename); // Only use the prefix set if database is present and non-empty. - if (!GetFileSizeOrZero(browse_filename)) + if (!GetFileSizeOrZero(db_filename)) return; // Cleanup any stale bloom filter (no longer used). // TODO(shess): Track existence to drive removal of this code? const base::FilePath bloom_filter_filename = - BloomFilterForFilename(browse_filename); + BloomFilterForFilename(db_filename); base::DeleteFile(bloom_filter_filename, false); const base::TimeTicks before = base::TimeTicks::Now(); - browse_prefix_set_ = safe_browsing::PrefixSet::LoadFile( - browse_prefix_set_filename); + *prefix_set = safe_browsing::PrefixSet::LoadFile(prefix_set_filename); UMA_HISTOGRAM_TIMES("SB2.PrefixSetLoad", base::TimeTicks::Now() - before); - if (!browse_prefix_set_.get()) - RecordFailure(FAILURE_BROWSE_PREFIX_SET_READ); + if (!prefix_set->get()) + RecordFailure(read_failure_type); } bool SafeBrowsingDatabaseNew::Delete() { @@ -1459,33 +1559,38 @@ bool SafeBrowsingDatabaseNew::Delete() { if (!r10) RecordFailure(FAILURE_IP_BLACKLIST_DELETE); - return r1 && r2 && r3 && r4 && r5 && r6 && r7 && r8 && r9 && r10; + const bool r11 = + base::DeleteFile(UnwantedSoftwareDBFilename(filename_base_), false); + if (!r11) + RecordFailure(FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_DELETE); + + return r1 && r2 && r3 && r4 && r5 && r6 && r7 && r8 && r9 && r10 && r11; } -void SafeBrowsingDatabaseNew::WritePrefixSet() { +void SafeBrowsingDatabaseNew::WritePrefixSet( + const base::FilePath& db_filename, + safe_browsing::PrefixSet* prefix_set, + FailureType write_failure_type) { DCHECK_EQ(creation_loop_, base::MessageLoop::current()); - if (!browse_prefix_set_.get()) + if (!prefix_set) return; - const base::FilePath browse_filename = BrowseDBFilename(filename_base_); - const base::FilePath browse_prefix_set_filename = - PrefixSetForFilename(browse_filename); + const base::FilePath prefix_set_filename = PrefixSetForFilename(db_filename); const base::TimeTicks before = base::TimeTicks::Now(); - const bool write_ok = browse_prefix_set_->WriteFile( - browse_prefix_set_filename); + const bool write_ok = prefix_set->WriteFile(prefix_set_filename); UMA_HISTOGRAM_TIMES("SB2.PrefixSetWrite", base::TimeTicks::Now() - before); - const int64 file_size = GetFileSizeOrZero(browse_prefix_set_filename); + const int64 file_size = GetFileSizeOrZero(prefix_set_filename); UMA_HISTOGRAM_COUNTS("SB2.PrefixSetKilobytes", static_cast(file_size / 1024)); if (!write_ok) - RecordFailure(FAILURE_BROWSE_PREFIX_SET_WRITE); + RecordFailure(write_failure_type); #if defined(OS_MACOSX) - base::mac::SetFileBackupExclusion(browse_prefix_set_filename); + base::mac::SetFileBackupExclusion(prefix_set_filename); #endif } diff --git a/chrome/browser/safe_browsing/safe_browsing_database.h b/chrome/browser/safe_browsing/safe_browsing_database.h index 3e2ca8d4147b5..c011b9bfc7a52 100644 --- a/chrome/browser/safe_browsing/safe_browsing_database.h +++ b/chrome/browser/safe_browsing/safe_browsing_database.h @@ -42,7 +42,9 @@ class SafeBrowsingDatabaseFactory { bool enable_download_whitelist, bool enable_extension_blacklist, bool enable_side_effect_free_whitelist, - bool enable_ip_blacklist) = 0; + bool enable_ip_blacklist, + bool enable_unwanted_software_list) = 0; + private: DISALLOW_COPY_AND_ASSIGN(SafeBrowsingDatabaseFactory); }; @@ -71,12 +73,15 @@ class SafeBrowsingDatabase { // database feature. // |enable_ip_blacklist| is used to control the csd malware IP blacklist // database feature. + // |enable_unwanted_software_list| is used to control the unwanted software + // list database feature. static SafeBrowsingDatabase* Create(bool enable_download_protection, bool enable_client_side_whitelist, bool enable_download_whitelist, bool enable_extension_blacklist, bool side_effect_free_whitelist, - bool enable_ip_blacklist); + bool enable_ip_blacklist, + bool enable_unwanted_software_list); // Makes the passed |factory| the factory used to instantiate // a SafeBrowsingDatabase. This is used for tests. @@ -93,14 +98,26 @@ class SafeBrowsingDatabase { virtual bool ResetDatabase() = 0; // Returns false if |url| is not in the browse database or already was cached - // as a miss. If it returns true, |prefix_hits| contains matching hash - // prefixes which had no cached results and |cache_hits| contains any matching - // cached gethash results. This function is safe to call from any thread. + // as a miss. If it returns true, |prefix_hits| contains sorted unique + // matching hash prefixes which had no cached results and |cache_hits| + // contains any matching cached gethash results. This function is safe to + // call from any thread. virtual bool ContainsBrowseUrl( const GURL& url, std::vector* prefix_hits, std::vector* cache_hits) = 0; + // Returns true iff the given url is on the unwanted software blacklist. + // Returns false if |url| is not in the browse database or already was cached + // as a miss. If it returns true, |prefix_hits| contains sorted unique + // matching hash prefixes which had no cached results and |cache_hits| + // contains any matching cached gethash results. This function is safe to + // call from any thread. + virtual bool ContainsUnwantedSoftwareUrl( + const GURL& url, + std::vector* prefix_hits, + std::vector* cache_hits) = 0; + // Returns false if none of |urls| are in Download database. If it returns // true, |prefix_hits| should contain the prefixes for the URLs that were in // the database. This function could ONLY be accessed from creation thread. @@ -218,6 +235,10 @@ class SafeBrowsingDatabase { static base::FilePath IpBlacklistDBFilename( const base::FilePath& ip_blacklist_base_filename); + // Filename for the unwanted software blacklist database. + static base::FilePath UnwantedSoftwareDBFilename( + const base::FilePath& db_filename); + // Enumerate failures for histogramming purposes. DO NOT CHANGE THE // ORDERING OF THESE VALUES. enum FailureType { @@ -235,7 +256,6 @@ class SafeBrowsingDatabase { FAILURE_DOWNLOAD_DATABASE_UPDATE_FINISH, FAILURE_WHITELIST_DATABASE_UPDATE_BEGIN, FAILURE_WHITELIST_DATABASE_UPDATE_FINISH, - FAILURE_BROWSE_PREFIX_SET_MISSING, FAILURE_BROWSE_PREFIX_SET_READ, FAILURE_BROWSE_PREFIX_SET_WRITE, FAILURE_BROWSE_PREFIX_SET_DELETE, @@ -252,6 +272,11 @@ class SafeBrowsingDatabase { FAILURE_IP_BLACKLIST_UPDATE_FINISH, FAILURE_IP_BLACKLIST_UPDATE_INVALID, FAILURE_IP_BLACKLIST_DELETE, + FAILURE_UNWANTED_SOFTWARE_DATABASE_UPDATE_BEGIN, + FAILURE_UNWANTED_SOFTWARE_DATABASE_UPDATE_FINISH, + FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_READ, + FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_WRITE, + FAILURE_UNWANTED_SOFTWARE_PREFIX_SET_DELETE, // Memory space for histograms is determined by the max. ALWAYS // ADD NEW VALUES BEFORE THIS ONE. @@ -281,7 +306,8 @@ class SafeBrowsingDatabaseNew : public SafeBrowsingDatabase { SafeBrowsingStore* download_whitelist_store, SafeBrowsingStore* extension_blacklist_store, SafeBrowsingStore* side_effect_free_whitelist_store, - SafeBrowsingStore* ip_blacklist_store); + SafeBrowsingStore* ip_blacklist_store, + SafeBrowsingStore* unwanted_software_store); // Create a database with a browse store. This is a legacy interface that // useds Sqlite. @@ -295,6 +321,10 @@ class SafeBrowsingDatabaseNew : public SafeBrowsingDatabase { bool ContainsBrowseUrl(const GURL& url, std::vector* prefix_hits, std::vector* cache_hits) override; + bool ContainsUnwantedSoftwareUrl( + const GURL& url, + std::vector* prefix_hits, + std::vector* cache_hits) override; bool ContainsDownloadUrl(const std::vector& urls, std::vector* prefix_hits) override; bool ContainsCsdWhitelistedUrl(const GURL& url) override; @@ -338,10 +368,24 @@ class SafeBrowsingDatabaseNew : public SafeBrowsingDatabase { // IPv6 IP prefix using SHA-1. typedef std::map > IPBlacklist; - // Helper for ContainsBrowseUrl, exposed for testing. - bool ContainsBrowseUrlHashes(const std::vector& full_hashes, - std::vector* prefix_hits, - std::vector* cache_hits); + bool PrefixSetContainsUrl( + const GURL& url, + scoped_ptr* prefix_set_getter, + std::vector* prefix_hits, + std::vector* cache_hits); + + // Exposed for testing of PrefixSetContainsUrlHashes() on the + // PrefixSet backing kMalwareList. + bool ContainsBrowseUrlHashesForTesting( + const std::vector& full_hashes, + std::vector* prefix_hits, + std::vector* cache_hits); + + bool PrefixSetContainsUrlHashes( + const std::vector& full_hashes, + scoped_ptr* prefix_set_getter, + std::vector* prefix_hits, + std::vector* cache_hits); // Returns true if the whitelist is disabled or if any of the given hashes // matches the whitelist. @@ -355,11 +399,19 @@ class SafeBrowsingDatabaseNew : public SafeBrowsingDatabase { // Deletes the files on disk. bool Delete(); - // Load the prefix set off disk, if available. - void LoadPrefixSet(); + // Load the prefix set in "|db_filename| Prefix Set" off disk, if available, + // and stores it in |prefix_set|. |read_failure_type| provides a + // caller-specific error code to be used on failure. + void LoadPrefixSet(const base::FilePath& db_filename, + scoped_ptr* prefix_set, + FailureType read_failure_type); - // Writes the current prefix set to disk. - void WritePrefixSet(); + // Writes the current prefix set "|db_filename| Prefix Set" on disk. + // |write_failure_type| provides a caller-specific error code to be used on + // failure. + void WritePrefixSet(const base::FilePath& db_filename, + safe_browsing::PrefixSet* prefix_set, + FailureType write_failure_type); // Loads the given full-length hashes to the given whitelist. If the number // of hashes is too large or if the kill switch URL is on the whitelist @@ -396,7 +448,20 @@ class SafeBrowsingDatabaseNew : public SafeBrowsingDatabase { int64 UpdateHashPrefixStore(const base::FilePath& store_filename, SafeBrowsingStore* store, FailureType failure_type); - void UpdateBrowseStore(); + + // Updates a PrefixStore store for URLs (|url_store|) which is backed on disk + // by a "|db_filename| Prefix Set" file. Specific failure types are provided + // to highlight the specific store who made the initial request on failure. + void UpdatePrefixSetUrlStore(const base::FilePath& db_filename, + SafeBrowsingStore* url_store, + scoped_ptr* prefix_set, + FailureType finish_failure_type, + FailureType write_failure_type); + + void UpdateUrlStore(SafeBrowsingStore* url_store, + scoped_ptr* prefix_set, + FailureType failure_type); + void UpdateSideEffectFreeWhitelistStore(); void UpdateWhitelistStore(const base::FilePath& store_filename, SafeBrowsingStore* store, @@ -407,10 +472,6 @@ class SafeBrowsingDatabaseNew : public SafeBrowsingDatabase { // object was created on. base::MessageLoop* creation_loop_; - // Lock for protecting access to variables that may be used on the IO thread. - // This includes |prefix_set_|, |browse_gethash_cache_|, |csd_whitelist_|. - base::Lock lookup_lock_; - // The base filename passed to Init(), used to generate the store and prefix // set filenames used to store data on disk. base::FilePath filename_base_; @@ -439,6 +500,14 @@ class SafeBrowsingDatabaseNew : public SafeBrowsingDatabase { // For IP blacklist. scoped_ptr ip_blacklist_store_; + // For unwanted software list. + scoped_ptr unwanted_software_store_; + + // Lock for protecting access to variables that may be used on the IO thread. + // This includes |(browse|unwanted_software)_prefix_set_|, + // |prefix_gethash_cache_|, |csd_whitelist_|. + base::Lock lookup_lock_; + SBWhitelist csd_whitelist_; SBWhitelist download_whitelist_; SBWhitelist extension_blacklist_; @@ -446,10 +515,10 @@ class SafeBrowsingDatabaseNew : public SafeBrowsingDatabase { // The IP blacklist should be small. At most a couple hundred IPs. IPBlacklist ip_blacklist_; - // Cache of gethash results for browse store. Entries should not be used if + // Cache of gethash results for prefix stores. Entries should not be used if // they are older than their expire_after field. Cached misses will have // empty full_hashes field. Cleared on each update. - std::map browse_gethash_cache_; + std::map prefix_gethash_cache_; // Set if corruption is detected during the course of an update. // Causes the update functions to fail with no side effects, until @@ -463,9 +532,12 @@ class SafeBrowsingDatabaseNew : public SafeBrowsingDatabase { // Used to check if a prefix was in the browse database. scoped_ptr browse_prefix_set_; - // Used to check if a prefix was in the browse database. + // Used to check if a prefix was in the side-effect free whitelist database. scoped_ptr side_effect_free_whitelist_prefix_set_; + // Used to check if a prexfix was in the unwanted software database. + scoped_ptr unwanted_software_prefix_set_; + // Used to schedule resetting the database because of corruption. base::WeakPtrFactory reset_factory_; }; diff --git a/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc index c09e53cc0d066..db83263ea44e9 100644 --- a/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc @@ -81,7 +81,7 @@ SBChunkData* BuildChunk(int chunk_number, } // Create add chunk with a single prefix. -SBChunkData* AddChunkPrefix(int chunk_number, SBPrefix prefix) { +SBChunkData* AddChunkPrefix(int chunk_number, SBPrefix prefix) { return BuildChunk(chunk_number, safe_browsing::ChunkData::ADD, safe_browsing::ChunkData::PREFIX_4B, &prefix, sizeof(prefix), @@ -259,10 +259,10 @@ class SafeBrowsingDatabaseTest : public PlatformTest { // Setup a database in a temporary directory. ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - database_.reset(new SafeBrowsingDatabaseNew); database_filename_ = temp_dir_.path().AppendASCII("SafeBrowsingTestDatabase"); - database_->Init(database_filename_); + + ResetAndReloadFullDatabase(); } void TearDown() override { @@ -271,6 +271,33 @@ class SafeBrowsingDatabaseTest : public PlatformTest { PlatformTest::TearDown(); } + // Reloads the |database_| in a new SafeBrowsingDatabaseNew object with all + // stores enabled. + void ResetAndReloadFullDatabase() { + SafeBrowsingStoreFile* browse_store = new SafeBrowsingStoreFile(); + SafeBrowsingStoreFile* download_store = new SafeBrowsingStoreFile(); + SafeBrowsingStoreFile* csd_whitelist_store = new SafeBrowsingStoreFile(); + SafeBrowsingStoreFile* download_whitelist_store = + new SafeBrowsingStoreFile(); + SafeBrowsingStoreFile* extension_blacklist_store = + new SafeBrowsingStoreFile(); + SafeBrowsingStoreFile* side_effect_free_whitelist_store = + new SafeBrowsingStoreFile(); + SafeBrowsingStoreFile* ip_blacklist_store = new SafeBrowsingStoreFile(); + SafeBrowsingStoreFile* unwanted_software_store = + new SafeBrowsingStoreFile(); + database_.reset( + new SafeBrowsingDatabaseNew(browse_store, + download_store, + csd_whitelist_store, + download_whitelist_store, + extension_blacklist_store, + side_effect_free_whitelist_store, + ip_blacklist_store, + unwanted_software_store)); + database_->Init(database_filename_); + } + void GetListsInfo(std::vector* lists) { lists->clear(); ASSERT_TRUE(database_->UpdateStarted(lists)); @@ -360,7 +387,7 @@ TEST_F(SafeBrowsingDatabaseTest, ListNameForBrowse) { database_->UpdateFinished(true); GetListsInfo(&lists); - ASSERT_EQ(2U, lists.size()); + ASSERT_LE(2U, lists.size()); EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name); EXPECT_EQ("1-3", lists[0].adds); EXPECT_EQ("7", lists[0].subs); @@ -370,24 +397,6 @@ TEST_F(SafeBrowsingDatabaseTest, ListNameForBrowse) { } TEST_F(SafeBrowsingDatabaseTest, ListNameForBrowseAndDownload) { - database_.reset(); - base::MessageLoop loop; - SafeBrowsingStoreFile* browse_store = new SafeBrowsingStoreFile(); - SafeBrowsingStoreFile* download_store = new SafeBrowsingStoreFile(); - SafeBrowsingStoreFile* csd_whitelist_store = new SafeBrowsingStoreFile(); - SafeBrowsingStoreFile* download_whitelist_store = new SafeBrowsingStoreFile(); - SafeBrowsingStoreFile* extension_blacklist_store = - new SafeBrowsingStoreFile(); - SafeBrowsingStoreFile* ip_blacklist_store = new SafeBrowsingStoreFile(); - database_.reset(new SafeBrowsingDatabaseNew(browse_store, - download_store, - csd_whitelist_store, - download_whitelist_store, - extension_blacklist_store, - NULL, - ip_blacklist_store)); - database_->Init(database_filename_); - ScopedVector chunks; std::vector lists; @@ -424,10 +433,14 @@ TEST_F(SafeBrowsingDatabaseTest, ListNameForBrowseAndDownload) { chunks.push_back(AddChunkHashedIpValue(9, "::ffff:192.168.1.0", 120)); database_->InsertChunks(safe_browsing_util::kIPBlacklist, chunks.get()); + chunks.clear(); + chunks.push_back(AddChunkPrefixValue(10, "www.unwanted.com/software.html")); + database_->InsertChunks(safe_browsing_util::kUnwantedUrlList, chunks.get()); + database_->UpdateFinished(true); GetListsInfo(&lists); - ASSERT_EQ(7U, lists.size()); + ASSERT_EQ(9U, lists.size()); EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name); EXPECT_EQ("1", lists[0].adds); EXPECT_TRUE(lists[0].subs.empty()); @@ -446,240 +459,272 @@ TEST_F(SafeBrowsingDatabaseTest, ListNameForBrowseAndDownload) { EXPECT_EQ(safe_browsing_util::kExtensionBlacklist, lists[5].name); EXPECT_EQ("8", lists[5].adds); EXPECT_TRUE(lists[5].subs.empty()); - EXPECT_EQ(safe_browsing_util::kIPBlacklist, lists[6].name); - EXPECT_EQ("9", lists[6].adds); - EXPECT_TRUE(lists[6].subs.empty()); + EXPECT_EQ(safe_browsing_util::kIPBlacklist, lists[7].name); + EXPECT_EQ("9", lists[7].adds); + EXPECT_TRUE(lists[7].subs.empty()); + EXPECT_EQ(safe_browsing_util::kUnwantedUrlList, lists[8].name); + EXPECT_EQ("10", lists[8].adds); + EXPECT_TRUE(lists[8].subs.empty()); database_.reset(); } -// Checks database reading and writing for browse. -TEST_F(SafeBrowsingDatabaseTest, BrowseDatabase) { - std::vector lists; - ScopedVector chunks; +// Checks database reading and writing for browse and unwanted PrefixSets. +TEST_F(SafeBrowsingDatabaseTest, BrowseAndUnwantedDatabasesAndPrefixSets) { + struct TestCase { + using TestListContainsBadUrl = bool (SafeBrowsingDatabase::*)( + const GURL& url, + std::vector* prefix_hits, + std::vector* cache_hits); + + const char* test_list_name; + size_t expected_list_index; + TestListContainsBadUrl test_list_contains_bad_url; + } const kTestCases[] { + { safe_browsing_util::kMalwareList, 0U, + &SafeBrowsingDatabase::ContainsBrowseUrl }, + { safe_browsing_util::kPhishingList, 1U, + &SafeBrowsingDatabase::ContainsBrowseUrl }, + { safe_browsing_util::kUnwantedUrlList, 8U, + &SafeBrowsingDatabase::ContainsUnwantedSoftwareUrl }, + }; - chunks.push_back(AddChunkPrefix2Value(1, - "www.evil.com/phishing.html", - "www.evil.com/malware.html")); - chunks.push_back(AddChunkPrefix4Value(2, - "www.evil.com/notevil1.html", - "www.evil.com/notevil2.html", - "www.good.com/good1.html", - "www.good.com/good2.html")); - chunks.push_back(AddChunkPrefixValue(3, "192.168.0.1/malware.html")); - chunks.push_back(AddChunkFullHashValue(7, "www.evil.com/evil.html")); + for (const auto& test_case : kTestCases) { + SCOPED_TRACE(std::string("Tested list at fault => ") + + test_case.test_list_name); - ASSERT_TRUE(database_->UpdateStarted(&lists)); - database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get()); - database_->UpdateFinished(true); + std::vector lists; + ScopedVector chunks; - // Make sure they were added correctly. - GetListsInfo(&lists); - ASSERT_LE(1U, lists.size()); - EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name); - EXPECT_EQ("1-3,7", lists[0].adds); - EXPECT_TRUE(lists[0].subs.empty()); + chunks.push_back(AddChunkPrefix2Value(1, + "www.evil.com/phishing.html", + "www.evil.com/malware.html")); + chunks.push_back(AddChunkPrefix4Value(2, + "www.evil.com/notevil1.html", + "www.evil.com/notevil2.html", + "www.good.com/good1.html", + "www.good.com/good2.html")); + chunks.push_back(AddChunkPrefixValue(3, "192.168.0.1/malware.html")); + chunks.push_back(AddChunkFullHashValue(7, "www.evil.com/evil.html")); - std::vector prefix_hits; - std::vector cache_hits; - EXPECT_TRUE(database_->ContainsBrowseUrl( - GURL("http://www.evil.com/phishing.html"), &prefix_hits, &cache_hits)); - ASSERT_EQ(1U, prefix_hits.size()); - EXPECT_EQ(SBPrefixForString("www.evil.com/phishing.html"), prefix_hits[0]); - EXPECT_TRUE(cache_hits.empty()); + ASSERT_TRUE(database_->UpdateStarted(&lists)); + database_->InsertChunks(test_case.test_list_name, chunks.get()); + database_->UpdateFinished(true); - EXPECT_TRUE(database_->ContainsBrowseUrl( - GURL("http://www.evil.com/malware.html"), &prefix_hits, &cache_hits)); + // Make sure they were added correctly. + GetListsInfo(&lists); - EXPECT_TRUE(database_->ContainsBrowseUrl( - GURL("http://www.evil.com/notevil1.html"), &prefix_hits, &cache_hits)); + ASSERT_LE(1U, lists.size()); + EXPECT_EQ(test_case.test_list_name, + lists[test_case.expected_list_index].name); + EXPECT_EQ("1-3,7", lists[test_case.expected_list_index].adds); + EXPECT_TRUE(lists[test_case.expected_list_index].subs.empty()); - EXPECT_TRUE(database_->ContainsBrowseUrl( - GURL("http://www.evil.com/notevil2.html"), &prefix_hits, &cache_hits)); + std::vector prefix_hits; + std::vector cache_hits; + EXPECT_TRUE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://www.evil.com/phishing.html"), &prefix_hits, &cache_hits)); + ASSERT_EQ(1U, prefix_hits.size()); + EXPECT_EQ(SBPrefixForString("www.evil.com/phishing.html"), prefix_hits[0]); + EXPECT_TRUE(cache_hits.empty()); - EXPECT_TRUE(database_->ContainsBrowseUrl( - GURL("http://www.good.com/good1.html"), &prefix_hits, &cache_hits)); + EXPECT_TRUE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://www.evil.com/malware.html"), &prefix_hits, &cache_hits)); - EXPECT_TRUE(database_->ContainsBrowseUrl( - GURL("http://www.good.com/good2.html"), &prefix_hits, &cache_hits)); + EXPECT_TRUE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://www.evil.com/notevil1.html"), &prefix_hits, &cache_hits)); - EXPECT_TRUE(database_->ContainsBrowseUrl( - GURL("http://192.168.0.1/malware.html"), &prefix_hits, &cache_hits)); + EXPECT_TRUE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://www.evil.com/notevil2.html"), &prefix_hits, &cache_hits)); - EXPECT_FALSE(database_->ContainsBrowseUrl( - GURL("http://www.evil.com/"), &prefix_hits, &cache_hits)); - EXPECT_TRUE(prefix_hits.empty()); - EXPECT_TRUE(cache_hits.empty()); + EXPECT_TRUE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://www.good.com/good1.html"), &prefix_hits, &cache_hits)); - EXPECT_FALSE(database_->ContainsBrowseUrl( - GURL("http://www.evil.com/robots.txt"), &prefix_hits, &cache_hits)); + EXPECT_TRUE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://www.good.com/good2.html"), &prefix_hits, &cache_hits)); - EXPECT_TRUE(database_->ContainsBrowseUrl( - GURL("http://www.evil.com/evil.html"), &prefix_hits, &cache_hits)); - ASSERT_EQ(1U, prefix_hits.size()); - EXPECT_EQ(SBPrefixForString("www.evil.com/evil.html"), prefix_hits[0]); + EXPECT_TRUE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://192.168.0.1/malware.html"), &prefix_hits, &cache_hits)); - // Attempt to re-add the first chunk (should be a no-op). - // see bug: http://code.google.com/p/chromium/issues/detail?id=4522 - chunks.clear(); - chunks.push_back(AddChunkPrefix2Value(1, - "www.evil.com/phishing.html", - "www.evil.com/malware.html")); - ASSERT_TRUE(database_->UpdateStarted(&lists)); - database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get()); - database_->UpdateFinished(true); + EXPECT_FALSE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://www.evil.com/"), &prefix_hits, &cache_hits)); + EXPECT_TRUE(prefix_hits.empty()); + EXPECT_TRUE(cache_hits.empty()); - GetListsInfo(&lists); - ASSERT_LE(1U, lists.size()); - EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name); - EXPECT_EQ("1-3,7", lists[0].adds); - EXPECT_TRUE(lists[0].subs.empty()); + EXPECT_FALSE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://www.evil.com/robots.txt"), &prefix_hits, &cache_hits)); - // Test removing a single prefix from the add chunk. - chunks.clear(); - chunks.push_back(SubChunkPrefixValue(4, "www.evil.com/notevil1.html", 2)); - ASSERT_TRUE(database_->UpdateStarted(&lists)); - database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get()); - database_->UpdateFinished(true); + EXPECT_TRUE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://www.evil.com/evil.html"), &prefix_hits, &cache_hits)); + ASSERT_EQ(1U, prefix_hits.size()); + EXPECT_EQ(SBPrefixForString("www.evil.com/evil.html"), prefix_hits[0]); + + // Attempt to re-add the first chunk (should be a no-op). + // see bug: http://code.google.com/p/chromium/issues/detail?id=4522 + chunks.clear(); + chunks.push_back(AddChunkPrefix2Value(1, + "www.evil.com/phishing.html", + "www.evil.com/malware.html")); + ASSERT_TRUE(database_->UpdateStarted(&lists)); + database_->InsertChunks(test_case.test_list_name, chunks.get()); + database_->UpdateFinished(true); - EXPECT_TRUE(database_->ContainsBrowseUrl( - GURL("http://www.evil.com/phishing.html"), &prefix_hits, &cache_hits)); - ASSERT_EQ(1U, prefix_hits.size()); - EXPECT_EQ(SBPrefixForString("www.evil.com/phishing.html"), prefix_hits[0]); - EXPECT_TRUE(cache_hits.empty()); + GetListsInfo(&lists); + ASSERT_LE(1U, lists.size()); + EXPECT_EQ(test_case.test_list_name, + lists[test_case.expected_list_index].name); + EXPECT_EQ("1-3,7", lists[test_case.expected_list_index].adds); + EXPECT_TRUE(lists[test_case.expected_list_index].subs.empty()); - EXPECT_FALSE(database_->ContainsBrowseUrl( - GURL("http://www.evil.com/notevil1.html"), &prefix_hits, &cache_hits)); - EXPECT_TRUE(prefix_hits.empty()); - EXPECT_TRUE(cache_hits.empty()); + // Test removing a single prefix from the add chunk. + chunks.clear(); + chunks.push_back(SubChunkPrefixValue(4, "www.evil.com/notevil1.html", 2)); + ASSERT_TRUE(database_->UpdateStarted(&lists)); + database_->InsertChunks(test_case.test_list_name, chunks.get()); + database_->UpdateFinished(true); - EXPECT_TRUE(database_->ContainsBrowseUrl( - GURL("http://www.evil.com/notevil2.html"), &prefix_hits, &cache_hits)); + EXPECT_TRUE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://www.evil.com/phishing.html"), &prefix_hits, &cache_hits)); + ASSERT_EQ(1U, prefix_hits.size()); + EXPECT_EQ(SBPrefixForString("www.evil.com/phishing.html"), prefix_hits[0]); + EXPECT_TRUE(cache_hits.empty()); - EXPECT_TRUE(database_->ContainsBrowseUrl( - GURL("http://www.good.com/good1.html"), &prefix_hits, &cache_hits)); + EXPECT_FALSE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://www.evil.com/notevil1.html"), &prefix_hits, &cache_hits)); + EXPECT_TRUE(prefix_hits.empty()); + EXPECT_TRUE(cache_hits.empty()); - EXPECT_TRUE(database_->ContainsBrowseUrl( - GURL("http://www.good.com/good2.html"), &prefix_hits, &cache_hits)); + EXPECT_TRUE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://www.evil.com/notevil2.html"), &prefix_hits, &cache_hits)); - GetListsInfo(&lists); - ASSERT_LE(1U, lists.size()); - EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name); - EXPECT_EQ("1-3,7", lists[0].adds); - EXPECT_EQ("4", lists[0].subs); + EXPECT_TRUE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://www.good.com/good1.html"), &prefix_hits, &cache_hits)); - // Test the same sub chunk again. This should be a no-op. - // see bug: http://code.google.com/p/chromium/issues/detail?id=4522 - chunks.clear(); - chunks.push_back(SubChunkPrefixValue(4, "www.evil.com/notevil1.html", 2)); + EXPECT_TRUE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://www.good.com/good2.html"), &prefix_hits, &cache_hits)); - ASSERT_TRUE(database_->UpdateStarted(&lists)); - database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get()); - database_->UpdateFinished(true); + GetListsInfo(&lists); + ASSERT_LE(1U, lists.size()); + EXPECT_EQ(test_case.test_list_name, + lists[test_case.expected_list_index].name); + EXPECT_EQ("1-3,7", lists[test_case.expected_list_index].adds); + EXPECT_EQ("4", lists[test_case.expected_list_index].subs); - GetListsInfo(&lists); - ASSERT_LE(1U, lists.size()); - EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name); - EXPECT_EQ("1-3,7", lists[0].adds); - EXPECT_EQ("4", lists[0].subs); + // Test the same sub chunk again. This should be a no-op. + // see bug: http://code.google.com/p/chromium/issues/detail?id=4522 + chunks.clear(); + chunks.push_back(SubChunkPrefixValue(4, "www.evil.com/notevil1.html", 2)); - // Test removing all the prefixes from an add chunk. - ASSERT_TRUE(database_->UpdateStarted(&lists)); - AddDelChunk(safe_browsing_util::kMalwareList, 2); - database_->UpdateFinished(true); + ASSERT_TRUE(database_->UpdateStarted(&lists)); + database_->InsertChunks(test_case.test_list_name, chunks.get()); + database_->UpdateFinished(true); - EXPECT_FALSE(database_->ContainsBrowseUrl( - GURL("http://www.evil.com/notevil2.html"), &prefix_hits, &cache_hits)); + GetListsInfo(&lists); + ASSERT_LE(1U, lists.size()); + EXPECT_EQ(test_case.test_list_name, + lists[test_case.expected_list_index].name); + EXPECT_EQ("1-3,7", lists[test_case.expected_list_index].adds); + EXPECT_EQ("4", lists[test_case.expected_list_index].subs); - EXPECT_FALSE(database_->ContainsBrowseUrl( - GURL("http://www.good.com/good1.html"), &prefix_hits, &cache_hits)); + // Test removing all the prefixes from an add chunk. + ASSERT_TRUE(database_->UpdateStarted(&lists)); + AddDelChunk(test_case.test_list_name, 2); + database_->UpdateFinished(true); - EXPECT_FALSE(database_->ContainsBrowseUrl( - GURL("http://www.good.com/good2.html"), &prefix_hits, &cache_hits)); + EXPECT_FALSE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://www.evil.com/notevil2.html"), &prefix_hits, &cache_hits)); - GetListsInfo(&lists); - ASSERT_LE(1U, lists.size()); - EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name); - EXPECT_EQ("1,3,7", lists[0].adds); - EXPECT_EQ("4", lists[0].subs); + EXPECT_FALSE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://www.good.com/good1.html"), &prefix_hits, &cache_hits)); - // The adddel command exposed a bug in the transaction code where any - // transaction after it would fail. Add a dummy entry and remove it to - // make sure the transcation works fine. - chunks.clear(); - chunks.push_back(AddChunkPrefixValue(44, "www.redherring.com/index.html")); - ASSERT_TRUE(database_->UpdateStarted(&lists)); - database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get()); + EXPECT_FALSE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://www.good.com/good2.html"), &prefix_hits, &cache_hits)); - // Now remove the dummy entry. If there are any problems with the - // transactions, asserts will fire. - AddDelChunk(safe_browsing_util::kMalwareList, 44); + GetListsInfo(&lists); + ASSERT_LE(1U, lists.size()); + EXPECT_EQ(test_case.test_list_name, + lists[test_case.expected_list_index].name); + EXPECT_EQ("1,3,7", lists[test_case.expected_list_index].adds); + EXPECT_EQ("4", lists[test_case.expected_list_index].subs); - // Test the subdel command. - SubDelChunk(safe_browsing_util::kMalwareList, 4); - database_->UpdateFinished(true); + // The adddel command exposed a bug in the transaction code where any + // transaction after it would fail. Add a dummy entry and remove it to + // make sure the transcation works fine. + chunks.clear(); + chunks.push_back(AddChunkPrefixValue(44, "www.redherring.com/index.html")); + ASSERT_TRUE(database_->UpdateStarted(&lists)); + database_->InsertChunks(test_case.test_list_name, chunks.get()); - GetListsInfo(&lists); - ASSERT_LE(1U, lists.size()); - EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name); - EXPECT_EQ("1,3,7", lists[0].adds); - EXPECT_TRUE(lists[0].subs.empty()); + // Now remove the dummy entry. If there are any problems with the + // transactions, asserts will fire. + AddDelChunk(test_case.test_list_name, 44); - // Test a sub command coming in before the add. - chunks.clear(); - chunks.push_back(SubChunkPrefix2Value(5, - "www.notevilanymore.com/index.html", - 10, - "www.notevilanymore.com/good.html", - 10)); - ASSERT_TRUE(database_->UpdateStarted(&lists)); - database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get()); - database_->UpdateFinished(true); + // Test the subdel command. + SubDelChunk(test_case.test_list_name, 4); + database_->UpdateFinished(true); - EXPECT_FALSE(database_->ContainsBrowseUrl( - GURL("http://www.notevilanymore.com/index.html"), - &prefix_hits, - &cache_hits)); + GetListsInfo(&lists); + ASSERT_LE(1U, lists.size()); + EXPECT_EQ(test_case.test_list_name, + lists[test_case.expected_list_index].name); + EXPECT_EQ("1,3,7", lists[test_case.expected_list_index].adds); + EXPECT_TRUE(lists[test_case.expected_list_index].subs.empty()); + + // Test a sub command coming in before the add. + chunks.clear(); + chunks.push_back(SubChunkPrefix2Value(5, + "www.notevilanymore.com/index.html", + 10, + "www.notevilanymore.com/good.html", + 10)); + ASSERT_TRUE(database_->UpdateStarted(&lists)); + database_->InsertChunks(test_case.test_list_name, chunks.get()); + database_->UpdateFinished(true); - // Now insert the tardy add chunk and we don't expect them to appear - // in database because of the previous sub chunk. - chunks.clear(); - chunks.push_back(AddChunkPrefix2Value(10, - "www.notevilanymore.com/index.html", - "www.notevilanymore.com/good.html")); - ASSERT_TRUE(database_->UpdateStarted(&lists)); - database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get()); - database_->UpdateFinished(true); + EXPECT_FALSE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://www.notevilanymore.com/index.html"), + &prefix_hits, + &cache_hits)); + + // Now insert the tardy add chunk and we don't expect them to appear + // in database because of the previous sub chunk. + chunks.clear(); + chunks.push_back(AddChunkPrefix2Value(10, + "www.notevilanymore.com/index.html", + "www.notevilanymore.com/good.html")); + ASSERT_TRUE(database_->UpdateStarted(&lists)); + database_->InsertChunks(test_case.test_list_name, chunks.get()); + database_->UpdateFinished(true); - EXPECT_FALSE(database_->ContainsBrowseUrl( - GURL("http://www.notevilanymore.com/index.html"), - &prefix_hits, - &cache_hits)); + EXPECT_FALSE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://www.notevilanymore.com/index.html"), + &prefix_hits, + &cache_hits)); - EXPECT_FALSE(database_->ContainsBrowseUrl( - GURL("http://www.notevilanymore.com/good.html"), - &prefix_hits, - &cache_hits)); + EXPECT_FALSE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://www.notevilanymore.com/good.html"), + &prefix_hits, + &cache_hits)); - // Reset and reload the database. The database will rely on the prefix set. - database_.reset(new SafeBrowsingDatabaseNew); - database_->Init(database_filename_); + // Reset and reload the database. The database will rely on the prefix set. + ResetAndReloadFullDatabase(); - // Check that a prefix still hits. - EXPECT_TRUE(database_->ContainsBrowseUrl( - GURL("http://www.evil.com/phishing.html"), &prefix_hits, &cache_hits)); - ASSERT_EQ(1U, prefix_hits.size()); - EXPECT_EQ(SBPrefixForString("www.evil.com/phishing.html"), prefix_hits[0]); + // Check that a prefix still hits. + EXPECT_TRUE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://www.evil.com/phishing.html"), &prefix_hits, &cache_hits)); + ASSERT_EQ(1U, prefix_hits.size()); + EXPECT_EQ(SBPrefixForString("www.evil.com/phishing.html"), prefix_hits[0]); - // Also check that it's not just always returning true in this case. - EXPECT_FALSE(database_->ContainsBrowseUrl( - GURL("http://www.evil.com/"), &prefix_hits, &cache_hits)); + // Also check that it's not just always returning true in this case. + EXPECT_FALSE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://www.evil.com/"), &prefix_hits, &cache_hits)); - // Check that the full hash is still present. - EXPECT_TRUE(database_->ContainsBrowseUrl( - GURL("http://www.evil.com/evil.html"), &prefix_hits, &cache_hits)); - ASSERT_EQ(1U, prefix_hits.size()); - EXPECT_EQ(SBPrefixForString("www.evil.com/evil.html"), prefix_hits[0]); + // Check that the full hash is still present. + EXPECT_TRUE((database_.get()->*test_case.test_list_contains_bad_url)( + GURL("http://www.evil.com/evil.html"), &prefix_hits, &cache_hits)); + ASSERT_EQ(1U, prefix_hits.size()); + EXPECT_EQ(SBPrefixForString("www.evil.com/evil.html"), prefix_hits[0]); + } } // Test adding zero length chunks to the database. @@ -786,7 +831,7 @@ void SafeBrowsingDatabaseTest::PopulateDatabaseForCacheTest() { database_->UpdateFinished(true); // Cache should be cleared after updating. - EXPECT_TRUE(database_->browse_gethash_cache_.empty()); + EXPECT_TRUE(database_->prefix_gethash_cache_.empty()); SBFullHashResult full_hash; full_hash.list_id = safe_browsing_util::MALWARE; @@ -810,7 +855,7 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) { PopulateDatabaseForCacheTest(); // We should have both full hashes in the cache. - EXPECT_EQ(2U, database_->browse_gethash_cache_.size()); + EXPECT_EQ(2U, database_->prefix_gethash_cache_.size()); // Test the cache lookup for the first prefix. std::vector prefix_hits; @@ -866,7 +911,7 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) { database_->UpdateFinished(true); EXPECT_FALSE(database_->ContainsBrowseUrl( GURL("http://www.evil.com/malware.html"), &prefix_hits, &cache_hits)); - EXPECT_TRUE(database_->browse_gethash_cache_.empty()); + EXPECT_TRUE(database_->prefix_gethash_cache_.empty()); prefix_hits.clear(); cache_hits.clear(); @@ -876,7 +921,7 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) { PopulateDatabaseForCacheTest(); std::map* hash_cache = - &database_->browse_gethash_cache_; + &database_->prefix_gethash_cache_; EXPECT_EQ(2U, hash_cache->size()); // Now adjust one of the entries times to be in the past. @@ -1051,7 +1096,7 @@ TEST_F(SafeBrowsingDatabaseTest, DISABLED_FileCorruptionHandling) { base::MessageLoop loop; SafeBrowsingStoreFile* store = new SafeBrowsingStoreFile(); database_.reset(new SafeBrowsingDatabaseNew(store, NULL, NULL, NULL, NULL, - NULL, NULL)); + NULL, NULL, NULL)); database_->Init(database_filename_); // This will cause an empty database to be created. @@ -1106,20 +1151,6 @@ TEST_F(SafeBrowsingDatabaseTest, DISABLED_FileCorruptionHandling) { // Checks database reading and writing. TEST_F(SafeBrowsingDatabaseTest, ContainsDownloadUrl) { - database_.reset(); - base::MessageLoop loop; - SafeBrowsingStoreFile* browse_store = new SafeBrowsingStoreFile(); - SafeBrowsingStoreFile* download_store = new SafeBrowsingStoreFile(); - SafeBrowsingStoreFile* csd_whitelist_store = new SafeBrowsingStoreFile(); - database_.reset(new SafeBrowsingDatabaseNew(browse_store, - download_store, - csd_whitelist_store, - NULL, - NULL, - NULL, - NULL)); - database_->Init(database_filename_); - const char kEvil1Url1[] = "www.evil1.com/download1/"; const char kEvil1Url2[] = "www.evil1.com/download2.html"; @@ -1217,7 +1248,7 @@ TEST_F(SafeBrowsingDatabaseTest, Whitelists) { // If the whitelist is disabled everything should match the whitelist. database_.reset(new SafeBrowsingDatabaseNew(new SafeBrowsingStoreFile(), NULL, NULL, NULL, NULL, NULL, - NULL)); + NULL, NULL)); database_->Init(database_filename_); EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl( GURL(std::string("http://www.phishing.com/")))); @@ -1225,17 +1256,7 @@ TEST_F(SafeBrowsingDatabaseTest, Whitelists) { GURL(std::string("http://www.phishing.com/")))); EXPECT_TRUE(database_->ContainsDownloadWhitelistedString("asdf")); - SafeBrowsingStoreFile* browse_store = new SafeBrowsingStoreFile(); - SafeBrowsingStoreFile* csd_whitelist_store = new SafeBrowsingStoreFile(); - SafeBrowsingStoreFile* download_whitelist_store = new SafeBrowsingStoreFile(); - SafeBrowsingStoreFile* extension_blacklist_store = - new SafeBrowsingStoreFile(); - database_.reset(new SafeBrowsingDatabaseNew(browse_store, NULL, - csd_whitelist_store, - download_whitelist_store, - extension_blacklist_store, - NULL, NULL)); - database_->Init(database_filename_); + ResetAndReloadFullDatabase(); const char kGood1Host[] = "www.good1.com/"; const char kGood1Url1[] = "www.good1.com/a/b.html"; @@ -1435,7 +1456,7 @@ TEST_F(SafeBrowsingDatabaseTest, SameHostEntriesOkay) { database_->UpdateFinished(true); GetListsInfo(&lists); - ASSERT_EQ(2U, lists.size()); + ASSERT_LE(2U, lists.size()); EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name); EXPECT_EQ("1", lists[0].adds); EXPECT_TRUE(lists[0].subs.empty()); @@ -1563,8 +1584,7 @@ TEST_F(SafeBrowsingDatabaseTest, FilterFile) { // After re-creating the database, it should have a filter read from // a file, so it should find the same results. ASSERT_TRUE(base::PathExists(filter_file)); - database_.reset(new SafeBrowsingDatabaseNew); - database_->Init(database_filename_); + ResetAndReloadFullDatabase(); EXPECT_TRUE(database_->ContainsBrowseUrl( GURL("http://www.evil.com/malware.html"), &prefix_hits, &cache_hits)); EXPECT_FALSE(database_->ContainsBrowseUrl( @@ -1573,8 +1593,7 @@ TEST_F(SafeBrowsingDatabaseTest, FilterFile) { // If there is no filter file, the database cannot find malware urls. base::DeleteFile(filter_file, false); ASSERT_FALSE(base::PathExists(filter_file)); - database_.reset(new SafeBrowsingDatabaseNew); - database_->Init(database_filename_); + ResetAndReloadFullDatabase(); EXPECT_FALSE(database_->ContainsBrowseUrl( GURL("http://www.evil.com/malware.html"), &prefix_hits, &cache_hits)); EXPECT_FALSE(database_->ContainsBrowseUrl( @@ -1613,14 +1632,14 @@ TEST_F(SafeBrowsingDatabaseTest, CachedFullMiss) { std::vector full_hashes(1, kFullHash1_1); std::vector prefix_hits; std::vector cache_hits; - EXPECT_FALSE(database_->ContainsBrowseUrlHashes( + EXPECT_FALSE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); // kFullHash2_1 gets a hit from the prefix in the database. full_hashes.push_back(kFullHash2_1); prefix_hits.clear(); cache_hits.clear(); - EXPECT_TRUE(database_->ContainsBrowseUrlHashes( + EXPECT_TRUE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); ASSERT_EQ(1U, prefix_hits.size()); EXPECT_EQ(kPrefix2, prefix_hits[0]); @@ -1661,7 +1680,7 @@ TEST_F(SafeBrowsingDatabaseTest, CachedPrefixHitFullMiss) { full_hashes.push_back(kFullHash1_1); std::vector prefix_hits; std::vector cache_hits; - EXPECT_TRUE(database_->ContainsBrowseUrlHashes( + EXPECT_TRUE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); ASSERT_EQ(1U, prefix_hits.size()); EXPECT_EQ(kPrefix1, prefix_hits[0]); @@ -1671,7 +1690,7 @@ TEST_F(SafeBrowsingDatabaseTest, CachedPrefixHitFullMiss) { full_hashes.push_back(kFullHash2_1); prefix_hits.clear(); cache_hits.clear(); - EXPECT_TRUE(database_->ContainsBrowseUrlHashes( + EXPECT_TRUE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); ASSERT_EQ(2U, prefix_hits.size()); EXPECT_EQ(kPrefix1, prefix_hits[0]); @@ -1682,7 +1701,7 @@ TEST_F(SafeBrowsingDatabaseTest, CachedPrefixHitFullMiss) { full_hashes.push_back(kFullHash3_1); prefix_hits.clear(); cache_hits.clear(); - EXPECT_TRUE(database_->ContainsBrowseUrlHashes( + EXPECT_TRUE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); ASSERT_EQ(2U, prefix_hits.size()); EXPECT_EQ(kPrefix1, prefix_hits[0]); @@ -1712,7 +1731,7 @@ TEST_F(SafeBrowsingDatabaseTest, CachedPrefixHitFullMiss) { std::vector full_hashes(1, kFullHash1_1); std::vector prefix_hits; std::vector cache_hits; - EXPECT_TRUE(database_->ContainsBrowseUrlHashes( + EXPECT_TRUE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); EXPECT_TRUE(prefix_hits.empty()); ASSERT_EQ(1U, cache_hits.size()); @@ -1723,7 +1742,7 @@ TEST_F(SafeBrowsingDatabaseTest, CachedPrefixHitFullMiss) { full_hashes.push_back(kFullHash2_1); prefix_hits.clear(); cache_hits.clear(); - EXPECT_TRUE(database_->ContainsBrowseUrlHashes( + EXPECT_TRUE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); ASSERT_EQ(1U, prefix_hits.size()); EXPECT_EQ(kPrefix2, prefix_hits[0]); @@ -1734,7 +1753,7 @@ TEST_F(SafeBrowsingDatabaseTest, CachedPrefixHitFullMiss) { full_hashes.push_back(kFullHash1_3); prefix_hits.clear(); cache_hits.clear(); - EXPECT_TRUE(database_->ContainsBrowseUrlHashes( + EXPECT_TRUE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); ASSERT_EQ(1U, prefix_hits.size()); EXPECT_EQ(kPrefix2, prefix_hits[0]); @@ -1748,7 +1767,7 @@ TEST_F(SafeBrowsingDatabaseTest, CachedPrefixHitFullMiss) { std::vector full_hashes(1, kFullHash1_3); std::vector prefix_hits; std::vector cache_hits; - EXPECT_TRUE(database_->ContainsBrowseUrlHashes( + EXPECT_TRUE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); EXPECT_TRUE(prefix_hits.empty()); ASSERT_EQ(1U, cache_hits.size()); @@ -1761,14 +1780,14 @@ TEST_F(SafeBrowsingDatabaseTest, CachedPrefixHitFullMiss) { std::vector full_hashes(1, kFullHash1_2); std::vector prefix_hits; std::vector cache_hits; - EXPECT_FALSE(database_->ContainsBrowseUrlHashes( + EXPECT_FALSE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); // Other prefix hits possible when kFullHash1_2 hits nothing. full_hashes.push_back(kFullHash2_1); prefix_hits.clear(); cache_hits.clear(); - EXPECT_TRUE(database_->ContainsBrowseUrlHashes( + EXPECT_TRUE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); ASSERT_EQ(1U, prefix_hits.size()); EXPECT_EQ(kPrefix2, prefix_hits[0]); @@ -1800,14 +1819,14 @@ TEST_F(SafeBrowsingDatabaseTest, BrowseFullHashMatching) { std::vector full_hashes(1, kFullHash1_3); std::vector prefix_hits; std::vector cache_hits; - EXPECT_FALSE(database_->ContainsBrowseUrlHashes( + EXPECT_FALSE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); // Also one which is present, should have a prefix hit. full_hashes.push_back(kFullHash1_1); prefix_hits.clear(); cache_hits.clear(); - EXPECT_TRUE(database_->ContainsBrowseUrlHashes( + EXPECT_TRUE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); ASSERT_EQ(1U, prefix_hits.size()); EXPECT_EQ(kPrefix1, prefix_hits[0]); @@ -1817,7 +1836,7 @@ TEST_F(SafeBrowsingDatabaseTest, BrowseFullHashMatching) { full_hashes.push_back(kFullHash1_2); prefix_hits.clear(); cache_hits.clear(); - EXPECT_TRUE(database_->ContainsBrowseUrlHashes( + EXPECT_TRUE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); ASSERT_EQ(1U, prefix_hits.size()); EXPECT_EQ(kPrefix1, prefix_hits[0]); @@ -1842,7 +1861,7 @@ TEST_F(SafeBrowsingDatabaseTest, BrowseFullHashMatching) { std::vector full_hashes(1, kFullHash1_3); std::vector prefix_hits; std::vector cache_hits; - EXPECT_FALSE(database_->ContainsBrowseUrlHashes( + EXPECT_FALSE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); // kFullHash1_1 is also not in the cached result, which takes @@ -1850,14 +1869,14 @@ TEST_F(SafeBrowsingDatabaseTest, BrowseFullHashMatching) { prefix_hits.clear(); full_hashes.push_back(kFullHash1_1); cache_hits.clear(); - EXPECT_FALSE(database_->ContainsBrowseUrlHashes( + EXPECT_FALSE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); // kFullHash1_2 is in the cached result. full_hashes.push_back(kFullHash1_2); prefix_hits.clear(); cache_hits.clear(); - EXPECT_TRUE(database_->ContainsBrowseUrlHashes( + EXPECT_TRUE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); EXPECT_TRUE(prefix_hits.empty()); ASSERT_EQ(1U, cache_hits.size()); @@ -1873,28 +1892,28 @@ TEST_F(SafeBrowsingDatabaseTest, BrowseFullHashMatching) { database_->UpdateFinished(true); // Cache should be cleared after updating. - EXPECT_TRUE(database_->browse_gethash_cache_.empty()); + EXPECT_TRUE(database_->prefix_gethash_cache_.empty()); { // Now the database doesn't contain kFullHash1_1. std::vector full_hashes(1, kFullHash1_1); std::vector prefix_hits; std::vector cache_hits; - EXPECT_FALSE(database_->ContainsBrowseUrlHashes( + EXPECT_FALSE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); // Nor kFullHash1_3. full_hashes.push_back(kFullHash1_3); prefix_hits.clear(); cache_hits.clear(); - EXPECT_FALSE(database_->ContainsBrowseUrlHashes( + EXPECT_FALSE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); // Still has kFullHash1_2. full_hashes.push_back(kFullHash1_2); prefix_hits.clear(); cache_hits.clear(); - EXPECT_TRUE(database_->ContainsBrowseUrlHashes( + EXPECT_TRUE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); ASSERT_EQ(1U, prefix_hits.size()); EXPECT_EQ(kPrefix1, prefix_hits[0]); @@ -1910,7 +1929,7 @@ TEST_F(SafeBrowsingDatabaseTest, BrowseFullHashMatching) { database_->UpdateFinished(true); // Cache should be cleared after updating. - EXPECT_TRUE(database_->browse_gethash_cache_.empty()); + EXPECT_TRUE(database_->prefix_gethash_cache_.empty()); { // None are present. @@ -1920,7 +1939,7 @@ TEST_F(SafeBrowsingDatabaseTest, BrowseFullHashMatching) { full_hashes.push_back(kFullHash1_1); full_hashes.push_back(kFullHash1_2); full_hashes.push_back(kFullHash1_3); - EXPECT_FALSE(database_->ContainsBrowseUrlHashes( + EXPECT_FALSE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); } } @@ -1945,7 +1964,7 @@ TEST_F(SafeBrowsingDatabaseTest, BrowseFullHashAndPrefixMatching) { std::vector full_hashes(1, kFullHash1_2); std::vector prefix_hits; std::vector cache_hits; - EXPECT_FALSE(database_->ContainsBrowseUrlHashes( + EXPECT_FALSE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); } @@ -1962,7 +1981,7 @@ TEST_F(SafeBrowsingDatabaseTest, BrowseFullHashAndPrefixMatching) { std::vector full_hashes(1, kFullHash1_2); std::vector prefix_hits; std::vector cache_hits; - EXPECT_TRUE(database_->ContainsBrowseUrlHashes( + EXPECT_TRUE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); ASSERT_EQ(1U, prefix_hits.size()); EXPECT_EQ(kPrefix1, prefix_hits[0]); @@ -1982,7 +2001,7 @@ TEST_F(SafeBrowsingDatabaseTest, BrowseFullHashAndPrefixMatching) { std::vector full_hashes(1, kFullHash1_2); std::vector prefix_hits; std::vector cache_hits; - EXPECT_TRUE(database_->ContainsBrowseUrlHashes( + EXPECT_TRUE(database_->ContainsBrowseUrlHashesForTesting( full_hashes, &prefix_hits, &cache_hits)); ASSERT_EQ(1U, prefix_hits.size()); EXPECT_EQ(kPrefix1, prefix_hits[0]); @@ -1991,17 +2010,6 @@ TEST_F(SafeBrowsingDatabaseTest, BrowseFullHashAndPrefixMatching) { } TEST_F(SafeBrowsingDatabaseTest, MalwareIpBlacklist) { - database_.reset(); - SafeBrowsingStoreFile* browse_store = new SafeBrowsingStoreFile(); - SafeBrowsingStoreFile* ip_blacklist_store = new SafeBrowsingStoreFile(); - database_.reset(new SafeBrowsingDatabaseNew(browse_store, - NULL, - NULL, - NULL, - NULL, - NULL, - ip_blacklist_store)); - database_->Init(database_filename_); std::vector lists; ASSERT_TRUE(database_->UpdateStarted(&lists)); diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc index 3137d061d1ff7..87f739e7d2af8 100644 --- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc @@ -134,6 +134,16 @@ class TestSafeBrowsingDatabase : public SafeBrowsingDatabase { std::vector(1, url), prefix_hits); } + bool ContainsUnwantedSoftwareUrl( + const GURL& url, + std::vector* prefix_hits, + std::vector* cache_hits) override { + cache_hits->clear(); + return ContainsUrl(safe_browsing_util::UNWANTEDURL, + safe_browsing_util::UNWANTEDURL, + std::vector(1, url), + prefix_hits); + } bool ContainsDownloadUrl(const std::vector& urls, std::vector* prefix_hits) override { bool found = ContainsUrl(safe_browsing_util::BINURL, @@ -186,8 +196,11 @@ class TestSafeBrowsingDatabase : public SafeBrowsingDatabase { void AddUrl(const GURL& url, int list_id, const std::vector& prefix_hits) { - badurls_[url.spec()].list_id = list_id; - badurls_[url.spec()].prefix_hits = prefix_hits; + Hits* hits_for_url = &badurls_[url.spec()]; + hits_for_url->list_ids.push_back(list_id); + hits_for_url->prefix_hits.insert(hits_for_url->prefix_hits.end(), + prefix_hits.begin(), + prefix_hits.end()); } // Fill up the database with test hash digest. @@ -196,8 +209,9 @@ class TestSafeBrowsingDatabase : public SafeBrowsingDatabase { } private: + // Stores |list_ids| of safe browsing lists that match some |prefix_hits|. struct Hits { - int list_id; + std::vector list_ids; std::vector prefix_hits; }; @@ -214,8 +228,11 @@ class TestSafeBrowsingDatabase : public SafeBrowsingDatabase { if (badurls_it == badurls_.end()) continue; - if (badurls_it->second.list_id == list_id0 || - badurls_it->second.list_id == list_id1) { + std::vector list_ids_for_url = badurls_it->second.list_ids; + if (std::find(list_ids_for_url.begin(), list_ids_for_url.end(), list_id0) + != list_ids_for_url.end() || + std::find(list_ids_for_url.begin(), list_ids_for_url.end(), list_id1) + != list_ids_for_url.end()) { prefix_hits->insert(prefix_hits->end(), badurls_it->second.prefix_hits.begin(), badurls_it->second.prefix_hits.end()); @@ -241,7 +258,8 @@ class TestSafeBrowsingDatabaseFactory : public SafeBrowsingDatabaseFactory { bool enable_download_whitelist, bool enable_extension_blacklist, bool enable_side_effect_free_whitelist, - bool enable_ip_blacklist) override { + bool enable_ip_blacklist, + bool enabled_unwanted_software_list) override { db_ = new TestSafeBrowsingDatabase(); return db_; } @@ -281,8 +299,7 @@ class TestProtocolManager : public SafeBrowsingProtocolManager { } // Prepare the GetFullHash results for the next request. - void SetGetFullHashResponse(const SBFullHashResult& full_hash_result) { - full_hashes_.clear(); + void AddGetFullHashResponse(const SBFullHashResult& full_hash_result) { full_hashes_.push_back(full_hash_result); } @@ -403,7 +420,8 @@ class SafeBrowsingServiceTest : public InProcessBrowserTest { } // This will setup the "url" prefix in database and prepare protocol manager - // to response with |full_hash| for get full hash request. + // to respond with |full_hash|, as well as other |full_hash|es previously set + // via this call, on GetFullHash requests. void SetupResponseForUrl(const GURL& url, const SBFullHashResult& full_hash) { std::vector prefix_hits; prefix_hits.push_back(full_hash.hash.prefix); @@ -414,7 +432,7 @@ class SafeBrowsingServiceTest : public InProcessBrowserTest { db->AddUrl(url, full_hash.list_id, prefix_hits); TestProtocolManager* pm = pm_factory_.GetProtocolManager(); - pm->SetGetFullHashResponse(full_hash); + pm->AddGetFullHashResponse(full_hash); } bool ShowingInterstitialPage() { @@ -724,24 +742,58 @@ class TestSBClient content::RunMessageLoop(); // Will stop in OnCheckDownloadUrlResult. } + void CheckBrowseUrl(const GURL& url) { + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(&TestSBClient::CheckBrowseUrlOnIOThread, this, url)); + content::RunMessageLoop(); // Will stop in OnCheckBrowseUrlResult. + } + private: friend class base::RefCountedThreadSafe; ~TestSBClient() override {} void CheckDownloadUrlOnIOThread(const std::vector& url_chain) { - safe_browsing_service_->database_manager()-> - CheckDownloadUrl(url_chain, this); + bool synchronous_safe_signal = + safe_browsing_service_->database_manager()->CheckDownloadUrl(url_chain, + this); + if (synchronous_safe_signal) { + threat_type_ = SB_THREAT_TYPE_SAFE; + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + base::Bind(&TestSBClient::CheckDone, this)); + } + } + + void CheckBrowseUrlOnIOThread(const GURL& url) { + // The async CheckDone() hook will not be called when we have a synchronous + // safe signal, handle it right away. + bool synchronous_safe_signal = + safe_browsing_service_->database_manager()->CheckBrowseUrl(url, this); + if (synchronous_safe_signal) { + threat_type_ = SB_THREAT_TYPE_SAFE; + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + base::Bind(&TestSBClient::CheckDone, this)); + } } // Called when the result of checking a download URL is known. - void OnCheckDownloadUrlResult(const std::vector& url_chain, + void OnCheckDownloadUrlResult(const std::vector& /* url_chain */, SBThreatType threat_type) override { threat_type_ = threat_type; BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(&TestSBClient::DownloadCheckDone, this)); + base::Bind(&TestSBClient::CheckDone, this)); + } + + // Called when the result of checking a browse URL is known. + void OnCheckBrowseUrlResult(const GURL& /* url */, + SBThreatType threat_type, + const std::string& /* metadata */) override { + threat_type_ = threat_type; + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + base::Bind(&TestSBClient::CheckDone, this)); } - void DownloadCheckDone() { + void CheckDone() { base::MessageLoopForUI::current()->Quit(); } @@ -776,6 +828,91 @@ IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, CheckDownloadUrl) { EXPECT_EQ(SB_THREAT_TYPE_BINARY_MALWARE_URL, client->GetThreatType()); } +IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, CheckUnwantedSoftwareUrl) { + const GURL bad_url = test_server()->GetURL(kMalwareFile); + { + scoped_refptr client(new TestSBClient); + + // Since bad_url is not in database, it is considered to be + // safe. + client->CheckBrowseUrl(bad_url); + EXPECT_EQ(SB_THREAT_TYPE_SAFE, client->GetThreatType()); + + SBFullHashResult full_hash_result; + GenUrlFullhashResult( + bad_url, safe_browsing_util::UNWANTEDURL, &full_hash_result); + SetupResponseForUrl(bad_url, full_hash_result); + + // Now, the bad_url is not safe since it is added to download + // database. + client->CheckBrowseUrl(bad_url); + EXPECT_EQ(SB_THREAT_TYPE_URL_UNWANTED, client->GetThreatType()); + } + + // The unwantedness should survive across multiple clients. + { + scoped_refptr client(new TestSBClient); + client->CheckBrowseUrl(bad_url); + EXPECT_EQ(SB_THREAT_TYPE_URL_UNWANTED, client->GetThreatType()); + } + + // An unwanted URL also marked as malware should be flagged as malware. + { + scoped_refptr client(new TestSBClient); + + SBFullHashResult full_hash_result; + GenUrlFullhashResult( + bad_url, safe_browsing_util::MALWARE, &full_hash_result); + SetupResponseForUrl(bad_url, full_hash_result); + + client->CheckBrowseUrl(bad_url); + EXPECT_EQ(SB_THREAT_TYPE_URL_MALWARE, client->GetThreatType()); + } +} + +IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, CheckBrowseUrl) { + const GURL bad_url = test_server()->GetURL(kMalwareFile); + { + scoped_refptr client(new TestSBClient); + + // Since bad_url is not in database, it is considered to be + // safe. + client->CheckBrowseUrl(bad_url); + EXPECT_EQ(SB_THREAT_TYPE_SAFE, client->GetThreatType()); + + SBFullHashResult full_hash_result; + GenUrlFullhashResult( + bad_url, safe_browsing_util::MALWARE, &full_hash_result); + SetupResponseForUrl(bad_url, full_hash_result); + + // Now, the bad_url is not safe since it is added to download + // database. + client->CheckBrowseUrl(bad_url); + EXPECT_EQ(SB_THREAT_TYPE_URL_MALWARE, client->GetThreatType()); + } + + // The unwantedness should survive across multiple clients. + { + scoped_refptr client(new TestSBClient); + client->CheckBrowseUrl(bad_url); + EXPECT_EQ(SB_THREAT_TYPE_URL_MALWARE, client->GetThreatType()); + } + + // Adding the unwanted state to an existing malware URL should have no impact + // (i.e. a malware hit should still prevail). + { + scoped_refptr client(new TestSBClient); + + SBFullHashResult full_hash_result; + GenUrlFullhashResult( + bad_url, safe_browsing_util::UNWANTEDURL, &full_hash_result); + SetupResponseForUrl(bad_url, full_hash_result); + + client->CheckBrowseUrl(bad_url); + EXPECT_EQ(SB_THREAT_TYPE_URL_MALWARE, client->GetThreatType()); + } +} + IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, CheckDownloadUrlRedirects) { GURL original_url = test_server()->GetURL(kEmptyPage); GURL badbin_url = test_server()->GetURL(kMalwareFile); diff --git a/chrome/browser/safe_browsing/safe_browsing_store_file.cc b/chrome/browser/safe_browsing/safe_browsing_store_file.cc index ff6448eabc0bc..298d42dd5bca5 100644 --- a/chrome/browser/safe_browsing/safe_browsing_store_file.cc +++ b/chrome/browser/safe_browsing/safe_browsing_store_file.cc @@ -618,10 +618,8 @@ bool SafeBrowsingStoreFile::CheckValidity() { return true; } -void SafeBrowsingStoreFile::Init( - const base::FilePath& filename, - const base::Closure& corruption_callback -) { +void SafeBrowsingStoreFile::Init(const base::FilePath& filename, + const base::Closure& corruption_callback) { filename_ = filename; corruption_callback_ = corruption_callback; } diff --git a/chrome/browser/safe_browsing/safe_browsing_util.cc b/chrome/browser/safe_browsing/safe_browsing_util.cc index bb2edf9a84414..b8f86d25024d9 100644 --- a/chrome/browser/safe_browsing/safe_browsing_util.cc +++ b/chrome/browser/safe_browsing/safe_browsing_util.cc @@ -189,16 +189,18 @@ const char kDownloadWhiteList[] = "goog-downloadwhite-digest256"; const char kExtensionBlacklist[] = "goog-badcrxids-digestvar"; const char kSideEffectFreeWhitelist[] = "goog-sideeffectfree-shavar"; const char kIPBlacklist[] = "goog-badip-digest256"; - -const char* kAllLists[8] = { - kMalwareList, - kPhishingList, - kBinUrlList, - kCsdWhiteList, - kDownloadWhiteList, - kExtensionBlacklist, - kSideEffectFreeWhitelist, - kIPBlacklist, +const char kUnwantedUrlList[] = "goog-unwanted-shavar"; + +const char* kAllLists[9] = { + kMalwareList, + kPhishingList, + kBinUrlList, + kCsdWhiteList, + kDownloadWhiteList, + kExtensionBlacklist, + kSideEffectFreeWhitelist, + kIPBlacklist, + kUnwantedUrlList, }; ListType GetListId(const base::StringPiece& name) { @@ -219,6 +221,8 @@ ListType GetListId(const base::StringPiece& name) { id = SIDEEFFECTFREEWHITELIST; } else if (name == safe_browsing_util::kIPBlacklist) { id = IPBLACKLIST; + } else if (name == safe_browsing_util::kUnwantedUrlList) { + id = UNWANTEDURL; } else { id = INVALID; } @@ -251,6 +255,9 @@ bool GetListName(ListType list_id, std::string* list) { case IPBLACKLIST: *list = safe_browsing_util::kIPBlacklist; break; + case UNWANTEDURL: + *list = safe_browsing_util::kUnwantedUrlList; + break; default: return false; } diff --git a/chrome/browser/safe_browsing/safe_browsing_util.h b/chrome/browser/safe_browsing/safe_browsing_util.h index b6ee9d06081dc..de877b041283b 100644 --- a/chrome/browser/safe_browsing/safe_browsing_util.h +++ b/chrome/browser/safe_browsing/safe_browsing_util.h @@ -133,8 +133,8 @@ enum SBThreatType { // The URL hosts malware. SB_THREAT_TYPE_URL_MALWARE, - // The URL hosts harmful programs. - SB_THREAT_TYPE_URL_HARMFUL, + // The URL hosts unwanted programs. + SB_THREAT_TYPE_URL_UNWANTED, // The download URL is malware. SB_THREAT_TYPE_BINARY_MALWARE_URL, @@ -170,9 +170,11 @@ extern const char kExtensionBlacklist[]; extern const char kSideEffectFreeWhitelist[]; // SafeBrowsing csd malware IP blacklist name. extern const char kIPBlacklist[]; +// SafeBrowsing unwanted URL list. +extern const char kUnwantedUrlList[]; // This array must contain all Safe Browsing lists. -extern const char* kAllLists[8]; +extern const char* kAllLists[9]; enum ListType { INVALID = -1, @@ -192,6 +194,8 @@ enum ListType { // See above comment. Leave 11 available. IPBLACKLIST = 12, // See above comment. Leave 13 available. + UNWANTEDURL = 14, + // See above comment. Leave 15 available. }; // Maps a list name to ListType. diff --git a/chrome/browser/search/contextual_search_policy_handler_android.cc b/chrome/browser/search/contextual_search_policy_handler_android.cc new file mode 100644 index 0000000000000..13f55024a1a5a --- /dev/null +++ b/chrome/browser/search/contextual_search_policy_handler_android.cc @@ -0,0 +1,39 @@ +// 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 "chrome/browser/search/contextual_search_policy_handler_android.h" + +#include "base/prefs/pref_value_map.h" +#include "base/values.h" +#include "chrome/common/pref_names.h" +#include "components/policy/core/common/policy_map.h" +#include "policy/policy_constants.h" + +namespace policy { + +ContextualSearchPolicyHandlerAndroid::ContextualSearchPolicyHandlerAndroid() + : TypeCheckingPolicyHandler(key::kContextualSearchEnabled, + base::Value::TYPE_BOOLEAN) {} + +ContextualSearchPolicyHandlerAndroid::~ContextualSearchPolicyHandlerAndroid() { +} + +void ContextualSearchPolicyHandlerAndroid::ApplyPolicySettings( + const PolicyMap& policies, + PrefValueMap* prefs) { + const base::Value* value = policies.GetValue(policy_name()); + bool contextual_search_enabled = true; + // From a Contextual Search preference point of view, "false" means the + // feature is turned off completely. "" means the feature is uninitialized and + // an opt-in screen is presented to the user, after which the preference is + // either "true" or "false", depending on their choice. Here a false policy + // explicitly disables Contextual Search. + if (value && + value->GetAsBoolean(&contextual_search_enabled) && + !contextual_search_enabled) { + prefs->SetString(prefs::kContextualSearchEnabled, "false"); + } +} + +} // namespace policy diff --git a/chrome/browser/search/contextual_search_policy_handler_android.h b/chrome/browser/search/contextual_search_policy_handler_android.h new file mode 100644 index 0000000000000..3794c200d3a5e --- /dev/null +++ b/chrome/browser/search/contextual_search_policy_handler_android.h @@ -0,0 +1,31 @@ +// 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 CHROME_BROWSER_SEARCH_CONTEXTUAL_SEARCH_POLICY_HANDLER_ANDROID_H_ +#define CHROME_BROWSER_SEARCH_CONTEXTUAL_SEARCH_POLICY_HANDLER_ANDROID_H_ + +#include "components/policy/core/browser/configuration_policy_handler.h" + +namespace policy { + +class PolicyMap; + +// ConfigurationPolicyHandler for the ContextualSearchEnabled policy. +class ContextualSearchPolicyHandlerAndroid + : public TypeCheckingPolicyHandler { + public: + ContextualSearchPolicyHandlerAndroid(); + ~ContextualSearchPolicyHandlerAndroid() override; + + // ConfigurationPolicyHandler methods: + void ApplyPolicySettings(const PolicyMap& policies, + PrefValueMap* prefs) override; + + private: + DISALLOW_COPY_AND_ASSIGN(ContextualSearchPolicyHandlerAndroid); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_SEARCH_CONTEXTUAL_SEARCH_POLICY_HANDLER_ANDROID_H_ diff --git a/chrome/browser/search/contextual_search_policy_handler_android_unittest.cc b/chrome/browser/search/contextual_search_policy_handler_android_unittest.cc new file mode 100644 index 0000000000000..1b494f0b96504 --- /dev/null +++ b/chrome/browser/search/contextual_search_policy_handler_android_unittest.cc @@ -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. + +#include "base/prefs/pref_value_map.h" +#include "base/values.h" +#include "chrome/browser/search/contextual_search_policy_handler_android.h" +#include "chrome/common/pref_names.h" +#include "components/policy/core/common/policy_map.h" +#include "policy/policy_constants.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace policy { + +TEST(ContextualSearchPolicyHandlerAndroidTest, Default) { + PolicyMap policy; + PrefValueMap prefs; + ContextualSearchPolicyHandlerAndroid handler; + handler.ApplyPolicySettings(policy, &prefs); + std::string pref_value; + EXPECT_FALSE(prefs.GetString(prefs::kContextualSearchEnabled, &pref_value)); + EXPECT_EQ("", pref_value); +} + +TEST(ContextualSearchPolicyHandlerAndroidTest, Enabled) { + PolicyMap policy; + policy.Set(key::kContextualSearchEnabled, + POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_USER, + new base::FundamentalValue(true), + NULL); + PrefValueMap prefs; + ContextualSearchPolicyHandlerAndroid handler; + handler.ApplyPolicySettings(policy, &prefs); + + // Enabling Contextual Search policy should not set the pref. + std::string pref_value; + EXPECT_FALSE(prefs.GetString(prefs::kContextualSearchEnabled, &pref_value)); + EXPECT_EQ("", pref_value); +} + +TEST(ContextualSearchPolicyHandlerAndroidTest, Disabled) { + PolicyMap policy; + policy.Set(key::kContextualSearchEnabled, + POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_USER, + new base::FundamentalValue(false), + NULL); + PrefValueMap prefs; + ContextualSearchPolicyHandlerAndroid handler; + handler.ApplyPolicySettings(policy, &prefs); + + // Disabling Contextual Search should switch the pref to managed. + std::string pref_value; + EXPECT_TRUE(prefs.GetString(prefs::kContextualSearchEnabled, &pref_value)); + EXPECT_EQ("false", pref_value); +} + +} // namespace policy diff --git a/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc b/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc index 656e88d113a3c..96d53cf45e4f0 100644 --- a/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc +++ b/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc @@ -69,6 +69,7 @@ bool TooltipContainsDeviceType(EasyUnlockScreenlockStateHandler::State state) { state == EasyUnlockScreenlockStateHandler::STATE_PHONE_UNLOCKABLE || state == EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH || state == EasyUnlockScreenlockStateHandler::STATE_PHONE_UNSUPPORTED || + state == EasyUnlockScreenlockStateHandler::STATE_RSSI_TOO_LOW || state == EasyUnlockScreenlockStateHandler::STATE_TX_POWER_TOO_HIGH; } @@ -118,6 +119,12 @@ void EasyUnlockScreenlockStateHandler::ChangeState(State new_state) { if (!screenlock_bridge_->IsLocked()) return; + // Do nothing when auth type is online. + if (screenlock_bridge_->lock_handler()->GetAuthType(user_email_) == + ScreenlockBridge::LockHandler::ONLINE_SIGN_IN) { + return; + } + // No hardlock UI for trial run. if (!is_trial_run_ && hardlock_state_ != NO_HARDLOCK) { ShowHardlockUI(); @@ -211,8 +218,13 @@ void EasyUnlockScreenlockStateHandler::ShowHardlockUI() { if (!screenlock_bridge_->IsLocked()) return; - if (screenlock_bridge_->lock_handler()->GetAuthType(user_email_) != - ScreenlockBridge::LockHandler::OFFLINE_PASSWORD) { + // Do not override online signin. + const ScreenlockBridge::LockHandler::AuthType existing_auth_type = + screenlock_bridge_->lock_handler()->GetAuthType(user_email_); + if (existing_auth_type == ScreenlockBridge::LockHandler::ONLINE_SIGN_IN) + return; + + if (existing_auth_type != ScreenlockBridge::LockHandler::OFFLINE_PASSWORD) { screenlock_bridge_->lock_handler()->SetAuthType( user_email_, ScreenlockBridge::LockHandler::OFFLINE_PASSWORD, @@ -231,6 +243,10 @@ void EasyUnlockScreenlockStateHandler::ShowHardlockUI() { ScreenlockBridge::UserPodCustomIconOptions icon_options; if (hardlock_state_ == LOGIN_FAILED) { icon_options.SetIcon(ScreenlockBridge::USER_POD_CUSTOM_ICON_LOCKED); + } else if (hardlock_state_ == PAIRING_CHANGED || + hardlock_state_ == PAIRING_ADDED) { + icon_options.SetIcon( + ScreenlockBridge::USER_POD_CUSTOM_ICON_LOCKED_TO_BE_ACTIVATED); } else { icon_options.SetIcon(ScreenlockBridge::USER_POD_CUSTOM_ICON_HARDLOCKED); } @@ -300,17 +316,21 @@ void EasyUnlockScreenlockStateHandler::UpdateScreenlockAuthType() { if (!is_trial_run_ && hardlock_state_ != NO_HARDLOCK) return; + // Do not override online signin. + const ScreenlockBridge::LockHandler::AuthType existing_auth_type = + screenlock_bridge_->lock_handler()->GetAuthType(user_email_); + DCHECK_NE(ScreenlockBridge::LockHandler::ONLINE_SIGN_IN, existing_auth_type); + if (state_ == STATE_AUTHENTICATED) { - if (screenlock_bridge_->lock_handler()->GetAuthType(user_email_) != - ScreenlockBridge::LockHandler::USER_CLICK) { + if (existing_auth_type != ScreenlockBridge::LockHandler::USER_CLICK) { screenlock_bridge_->lock_handler()->SetAuthType( user_email_, ScreenlockBridge::LockHandler::USER_CLICK, l10n_util::GetStringUTF16( IDS_EASY_UNLOCK_SCREENLOCK_USER_POD_AUTH_VALUE)); } - } else if (screenlock_bridge_->lock_handler()->GetAuthType(user_email_) != - ScreenlockBridge::LockHandler::OFFLINE_PASSWORD) { + } else if (existing_auth_type != + ScreenlockBridge::LockHandler::OFFLINE_PASSWORD) { screenlock_bridge_->lock_handler()->SetAuthType( user_email_, ScreenlockBridge::LockHandler::OFFLINE_PASSWORD, diff --git a/chrome/browser/signin/easy_unlock_screenlock_state_handler_unittest.cc b/chrome/browser/signin/easy_unlock_screenlock_state_handler_unittest.cc index 4c0e89befaffe..36c18b440bd42 100644 --- a/chrome/browser/signin/easy_unlock_screenlock_state_handler_unittest.cc +++ b/chrome/browser/signin/easy_unlock_screenlock_state_handler_unittest.cc @@ -20,6 +20,7 @@ namespace { // Icons used by EasyUnlockScreenlockStateHandler. The icon id values are the // same as the ones set by ScreenlockBridge. const char kLockedIconId[] = "locked"; +const char kLockedToBeActivatedIconId[] = "locked-to-be-activated"; const char kUnlockedIconId[] = "unlocked"; const char kSpinnerIconId[] = "spinner"; const char kHardlockedIconId[] = "hardlocked"; @@ -565,14 +566,14 @@ TEST_F(EasyUnlockScreenlockStateHandlerTest, PairingChangedHardlock) { EXPECT_EQ(1u, lock_handler_->GetAndResetShowIconCount()); ASSERT_TRUE(lock_handler_->HasCustomIcon()); - EXPECT_EQ(kHardlockedIconId, lock_handler_->GetCustomIconId()); + EXPECT_EQ(kLockedToBeActivatedIconId, lock_handler_->GetCustomIconId()); state_handler_->ChangeState( EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED); EXPECT_EQ(0u, lock_handler_->GetAndResetShowIconCount()); ASSERT_TRUE(lock_handler_->HasCustomIcon()); - EXPECT_EQ(kHardlockedIconId, lock_handler_->GetCustomIconId()); + EXPECT_EQ(kLockedToBeActivatedIconId, lock_handler_->GetCustomIconId()); } TEST_F(EasyUnlockScreenlockStateHandlerTest, @@ -744,4 +745,46 @@ TEST_F(EasyUnlockScreenlockStateHandlerTest, HardlockStatePersistsOverUnlocks) { lock_handler_->GetAuthType(user_email_)); } +TEST_F(EasyUnlockScreenlockStateHandlerTest, NoOverrideOnlineSignin) { + lock_handler_->SetAuthType(user_email_, + ScreenlockBridge::LockHandler::ONLINE_SIGN_IN, + base::string16()); + + std::vector states; + states.push_back(EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH); + states.push_back(EasyUnlockScreenlockStateHandler::STATE_NO_PHONE); + states.push_back(EasyUnlockScreenlockStateHandler::STATE_PHONE_UNSUPPORTED); + states.push_back(EasyUnlockScreenlockStateHandler::STATE_PHONE_UNLOCKABLE); + states.push_back( + EasyUnlockScreenlockStateHandler::STATE_PHONE_NOT_AUTHENTICATED); + states.push_back(EasyUnlockScreenlockStateHandler::STATE_PHONE_LOCKED); + states.push_back(EasyUnlockScreenlockStateHandler::STATE_PHONE_UNLOCKABLE); + states.push_back(EasyUnlockScreenlockStateHandler::STATE_PHONE_UNSUPPORTED); + states.push_back(EasyUnlockScreenlockStateHandler::STATE_RSSI_TOO_LOW); + states.push_back(EasyUnlockScreenlockStateHandler::STATE_TX_POWER_TOO_HIGH); + states.push_back(EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED); + + for (size_t i = 0; i < states.size(); ++i) { + state_handler_->ChangeState(states[i]); + EXPECT_EQ(ScreenlockBridge::LockHandler::ONLINE_SIGN_IN, + lock_handler_->GetAuthType(user_email_)); + EXPECT_FALSE(lock_handler_->HasCustomIcon()); + } + + std::vector hardlock_states; + hardlock_states.push_back(EasyUnlockScreenlockStateHandler::NO_HARDLOCK); + hardlock_states.push_back(EasyUnlockScreenlockStateHandler::USER_HARDLOCK); + hardlock_states.push_back(EasyUnlockScreenlockStateHandler::PAIRING_CHANGED); + hardlock_states.push_back(EasyUnlockScreenlockStateHandler::PAIRING_ADDED); + hardlock_states.push_back(EasyUnlockScreenlockStateHandler::NO_PAIRING); + hardlock_states.push_back(EasyUnlockScreenlockStateHandler::LOGIN_FAILED); + + for (size_t i = 0; i < hardlock_states.size(); ++i) { + state_handler_->SetHardlockState(hardlock_states[i]); + EXPECT_EQ(ScreenlockBridge::LockHandler::ONLINE_SIGN_IN, + lock_handler_->GetAuthType(user_email_)); + EXPECT_FALSE(lock_handler_->HasCustomIcon()); + } +} + } // namespace diff --git a/chrome/browser/signin/easy_unlock_service.cc b/chrome/browser/signin/easy_unlock_service.cc index 794941ea0176f..9281513ebdad0 100644 --- a/chrome/browser/signin/easy_unlock_service.cc +++ b/chrome/browser/signin/easy_unlock_service.cc @@ -301,13 +301,14 @@ bool EasyUnlockService::GetPersistedHardlockState( } void EasyUnlockService::ShowInitialUserState() { + if (!GetScreenlockStateHandler()) + return; + EasyUnlockScreenlockStateHandler::HardlockState state; bool has_persisted_state = GetPersistedHardlockState(&state); if (!has_persisted_state) return; - GetScreenlockStateHandler(); - if (state == EasyUnlockScreenlockStateHandler::NO_HARDLOCK) { // Show connecting icon early when there is a persisted non hardlock state. UpdateScreenlockState( diff --git a/chrome/browser/signin/easy_unlock_toggle_flow.cc b/chrome/browser/signin/easy_unlock_toggle_flow.cc index bb277644d3115..738d6e7a4484d 100644 --- a/chrome/browser/signin/easy_unlock_toggle_flow.cc +++ b/chrome/browser/signin/easy_unlock_toggle_flow.cc @@ -10,6 +10,7 @@ #include "base/strings/stringprintf.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/signin/chrome_signin_client_factory.h" #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" #include "chrome/browser/signin/signin_manager_factory.h" #include "chrome/common/extensions/extension_constants.h" @@ -145,13 +146,17 @@ void EasyUnlockToggleFlow::OnGetTokenSuccess( DCHECK_EQ(token_request_.get(), request); token_request_.reset(); - mint_token_flow_.reset( - new OAuth2MintTokenFlow(this, - OAuth2MintTokenFlow::Parameters( - extension_misc::kEasyUnlockAppId, - GetEasyUnlockAppClientId(profile_), - GetScopes(), - OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE))); + SigninClient* signin_client = + ChromeSigninClientFactory::GetForProfile(profile_); + std::string signin_scoped_device_id = + signin_client->GetSigninScopedDeviceId(); + + mint_token_flow_.reset(new OAuth2MintTokenFlow( + this, + OAuth2MintTokenFlow::Parameters( + extension_misc::kEasyUnlockAppId, GetEasyUnlockAppClientId(profile_), + GetScopes(), signin_scoped_device_id, + OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE))); mint_token_flow_->Start(profile_->GetRequestContext(), access_token); } diff --git a/chrome/browser/signin/screenlock_bridge.cc b/chrome/browser/signin/screenlock_bridge.cc index b11b51e57f8ea..1883814d69eb3 100644 --- a/chrome/browser/signin/screenlock_bridge.cc +++ b/chrome/browser/signin/screenlock_bridge.cc @@ -24,6 +24,7 @@ base::LazyInstance g_screenlock_bridge_bridge_instance = // account picker as user pod custom icons. // The id's should be kept in sync with values used by user_pod_row.js. const char kLockedUserPodCustomIconId[] = "locked"; +const char kLockedToBeActivatedUserPodCustomIconId[] = "locked-to-be-activated"; const char kLockedWithProximityHintUserPodCustomIconId[] = "locked-with-proximity-hint"; const char kUnlockedUserPodCustomIconId[] = "unlocked"; @@ -35,6 +36,8 @@ std::string GetIdForIcon(ScreenlockBridge::UserPodCustomIcon icon) { switch (icon) { case ScreenlockBridge::USER_POD_CUSTOM_ICON_LOCKED: return kLockedUserPodCustomIconId; + case ScreenlockBridge::USER_POD_CUSTOM_ICON_LOCKED_TO_BE_ACTIVATED: + return kLockedToBeActivatedUserPodCustomIconId; case ScreenlockBridge::USER_POD_CUSTOM_ICON_LOCKED_WITH_PROXIMITY_HINT: return kLockedWithProximityHintUserPodCustomIconId; case ScreenlockBridge::USER_POD_CUSTOM_ICON_UNLOCKED: diff --git a/chrome/browser/signin/screenlock_bridge.h b/chrome/browser/signin/screenlock_bridge.h index bf778327bbb88..1cfba53629122 100644 --- a/chrome/browser/signin/screenlock_bridge.h +++ b/chrome/browser/signin/screenlock_bridge.h @@ -42,6 +42,7 @@ class ScreenlockBridge { USER_POD_CUSTOM_ICON_NONE, USER_POD_CUSTOM_ICON_HARDLOCKED, USER_POD_CUSTOM_ICON_LOCKED, + USER_POD_CUSTOM_ICON_LOCKED_TO_BE_ACTIVATED, // TODO(isherman): The "locked with proximity hint" icon is currently the // same as the "locked" icon. It's treated as a separate case to allow an // easy asset swap without changing the code, in case we decide to use a diff --git a/chrome/browser/ssl/ssl_error_info.cc b/chrome/browser/ssl/ssl_error_info.cc index 80aaf9b6c1c1e..9737bdf6642ba 100644 --- a/chrome/browser/ssl/ssl_error_info.cc +++ b/chrome/browser/ssl/ssl_error_info.cc @@ -145,13 +145,6 @@ SSLErrorInfo SSLErrorInfo::CreateError(ErrorType error_type, short_description = l10n_util::GetStringUTF16( IDS_CERT_ERROR_NAME_CONSTRAINT_VIOLATION_DESCRIPTION); break; - case CERT_VALIDITY_TOO_LONG: - details = - l10n_util::GetStringFUTF16(IDS_CERT_ERROR_VALIDITY_TOO_LONG_DETAILS, - UTF8ToUTF16(request_url.host())); - short_description = l10n_util::GetStringUTF16( - IDS_CERT_ERROR_VALIDITY_TOO_LONG_DESCRIPTION); - break; case CERT_PINNED_KEY_MISSING: details = l10n_util::GetStringUTF16( IDS_ERRORPAGES_SUMMARY_PINNING_FAILURE); @@ -198,8 +191,6 @@ SSLErrorInfo::ErrorType SSLErrorInfo::NetErrorToErrorType(int net_error) { return CERT_WEAK_KEY; case net::ERR_CERT_NAME_CONSTRAINT_VIOLATION: return CERT_NAME_CONSTRAINT_VIOLATION; - case net::ERR_CERT_VALIDITY_TOO_LONG: - return CERT_VALIDITY_TOO_LONG; case net::ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY: return CERT_WEAK_KEY_DH; case net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN: @@ -216,31 +207,29 @@ int SSLErrorInfo::GetErrorsForCertStatus(int cert_id, const GURL& url, std::vector* errors) { const net::CertStatus kErrorFlags[] = { - net::CERT_STATUS_COMMON_NAME_INVALID, - net::CERT_STATUS_DATE_INVALID, - net::CERT_STATUS_AUTHORITY_INVALID, - net::CERT_STATUS_NO_REVOCATION_MECHANISM, - net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION, - net::CERT_STATUS_REVOKED, - net::CERT_STATUS_INVALID, - net::CERT_STATUS_WEAK_SIGNATURE_ALGORITHM, - net::CERT_STATUS_WEAK_KEY, - net::CERT_STATUS_NAME_CONSTRAINT_VIOLATION, - net::CERT_STATUS_VALIDITY_TOO_LONG, + net::CERT_STATUS_COMMON_NAME_INVALID, + net::CERT_STATUS_DATE_INVALID, + net::CERT_STATUS_AUTHORITY_INVALID, + net::CERT_STATUS_NO_REVOCATION_MECHANISM, + net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION, + net::CERT_STATUS_REVOKED, + net::CERT_STATUS_INVALID, + net::CERT_STATUS_WEAK_SIGNATURE_ALGORITHM, + net::CERT_STATUS_WEAK_KEY, + net::CERT_STATUS_NAME_CONSTRAINT_VIOLATION, }; const ErrorType kErrorTypes[] = { - CERT_COMMON_NAME_INVALID, - CERT_DATE_INVALID, - CERT_AUTHORITY_INVALID, - CERT_NO_REVOCATION_MECHANISM, - CERT_UNABLE_TO_CHECK_REVOCATION, - CERT_REVOKED, - CERT_INVALID, - CERT_WEAK_SIGNATURE_ALGORITHM, - CERT_WEAK_KEY, - CERT_NAME_CONSTRAINT_VIOLATION, - CERT_VALIDITY_TOO_LONG, + CERT_COMMON_NAME_INVALID, + CERT_DATE_INVALID, + CERT_AUTHORITY_INVALID, + CERT_NO_REVOCATION_MECHANISM, + CERT_UNABLE_TO_CHECK_REVOCATION, + CERT_REVOKED, + CERT_INVALID, + CERT_WEAK_SIGNATURE_ALGORITHM, + CERT_WEAK_KEY, + CERT_NAME_CONSTRAINT_VIOLATION, }; DCHECK(arraysize(kErrorFlags) == arraysize(kErrorTypes)); @@ -254,10 +243,9 @@ int SSLErrorInfo::GetErrorsForCertStatus(int cert_id, cert_id, &cert); DCHECK(r); } - if (errors) { + if (errors) errors->push_back( SSLErrorInfo::CreateError(kErrorTypes[i], cert.get(), url)); - } } } return count; diff --git a/chrome/browser/ssl/ssl_error_info.h b/chrome/browser/ssl/ssl_error_info.h index 29803059597dd..bcc169aec773f 100644 --- a/chrome/browser/ssl/ssl_error_info.h +++ b/chrome/browser/ssl/ssl_error_info.h @@ -33,7 +33,6 @@ class SSLErrorInfo { CERT_WEAK_SIGNATURE_ALGORITHM, CERT_WEAK_KEY, CERT_NAME_CONSTRAINT_VIOLATION, - CERT_VALIDITY_TOO_LONG, UNKNOWN, CERT_WEAK_KEY_DH, CERT_PINNED_KEY_MISSING, diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc index 9fb4b92903364..29deb31eba0d4 100644 --- a/chrome/browser/sync/profile_sync_service.cc +++ b/chrome/browser/sync/profile_sync_service.cc @@ -188,6 +188,15 @@ void ClearBrowsingData(BrowsingDataRemover::Observer* observer, password->RemoveLoginsSyncedBetween(start, end); } +// Perform the actual sync data folder deletion. +// This should only be called on the sync thread. +void DeleteSyncDataFolder(const base::FilePath& directory_path) { + if (base::DirectoryExists(directory_path)) { + if (!base::DeleteFile(directory_path, true)) + LOG(DFATAL) << "Could not delete the Sync Data folder."; + } +} + } // anonymous namespace bool ShouldShowActionOnUI( @@ -671,6 +680,8 @@ void ProfileSyncService::StartUpSlowBackendComponents( invalidator = provider->GetInvalidationService(); } + directory_path_ = profile_->GetPath().Append(sync_folder); + backend_.reset( factory_->CreateSyncBackendHost( profile_->GetDebugName(), @@ -807,8 +818,15 @@ void ProfileSyncService::Shutdown() { } void ProfileSyncService::ShutdownImpl(syncer::ShutdownReason reason) { - if (!backend_) + if (!backend_) { + if (reason == syncer::ShutdownReason::DISABLE_SYNC && sync_thread_) { + // If the backend is already shut down when a DISABLE_SYNC happens, + // the data directory needs to be cleaned up here. + sync_thread_->message_loop()->PostTask(FROM_HERE, + base::Bind(&DeleteSyncDataFolder, directory_path_)); + } return; + } non_blocking_data_type_manager_.DisconnectSyncBackend(); @@ -2737,3 +2755,17 @@ void ProfileSyncService::FlushDirectory() const { if (backend_initialized_) backend_->FlushDirectory(); } + +base::FilePath ProfileSyncService::GetDirectoryPathForTest() const { + return directory_path_; +} + +base::MessageLoop* ProfileSyncService::GetSyncLoopForTest() const { + if (sync_thread_) { + return sync_thread_->message_loop(); + } else if (backend_) { + return backend_->GetSyncLoopForTesting(); + } else { + return NULL; + } +} diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h index a8bcc3c3cd035..5c499a6e7e7c9 100644 --- a/chrome/browser/sync/profile_sync_service.h +++ b/chrome/browser/sync/profile_sync_service.h @@ -11,6 +11,7 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" +#include "base/files/file_path.h" #include "base/gtest_prod_util.h" #include "base/location.h" #include "base/memory/scoped_ptr.h" @@ -788,6 +789,12 @@ class ProfileSyncService : public ProfileSyncServiceBase, // killed in the near future. void FlushDirectory() const; + // Needed to test whether the directory is deleted properly. + base::FilePath GetDirectoryPathForTest() const; + + // Sometimes we need to wait for tasks on the sync thread in tests. + base::MessageLoop* GetSyncLoopForTest() const; + protected: // Helper to configure the priority data types. void ConfigurePriorityDataTypes(); @@ -973,7 +980,7 @@ class ProfileSyncService : public ProfileSyncServiceBase, // Clean up prefs and backup DB when rollback is not needed. void CleanUpBackup(); - // Factory used to create various dependent objects. + // Factory used to create various dependent objects. scoped_ptr factory_; // The profile whose data we are synchronizing. @@ -1156,6 +1163,9 @@ class ProfileSyncService : public ProfileSyncServiceBase, BrowsingDataRemover::Observer* browsing_data_remover_observer_; + // The full path to the sync data directory. + base::FilePath directory_path_; + DISALLOW_COPY_AND_ASSIGN(ProfileSyncService); }; diff --git a/chrome/browser/sync/test/integration/single_client_directory_sync_test.cc b/chrome/browser/sync/test/integration/single_client_directory_sync_test.cc new file mode 100644 index 0000000000000..964707d9d95bf --- /dev/null +++ b/chrome/browser/sync/test/integration/single_client_directory_sync_test.cc @@ -0,0 +1,53 @@ +// Copyright (c) 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/synchronization/waitable_event.h" +#include "base/time/time.h" +#include "chrome/browser/sync/profile_sync_service.h" +#include "chrome/browser/sync/test/integration/sync_test.h" +#include "content/public/browser/browser_thread.h" + +using content::BrowserThread; + +class SingleClientDirectorySyncTest : public SyncTest { + public: + SingleClientDirectorySyncTest() : SyncTest(SINGLE_CLIENT) {} + virtual ~SingleClientDirectorySyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(SingleClientDirectorySyncTest); +}; + +void SignalEvent(base::WaitableEvent* e) { + e->Signal(); +} + +bool WaitForExistingTasksOnLoop(base::MessageLoop* loop) { + base::WaitableEvent e(true, false); + loop->PostTask(FROM_HERE, base::Bind(&SignalEvent, &e)); + // Timeout stolen from StatusChangeChecker::GetTimeoutDuration(). + return e.TimedWait(base::TimeDelta::FromSeconds(45)); +} + +IN_PROC_BROWSER_TEST_F(SingleClientDirectorySyncTest, + StopThenDisableDeletesDirectory) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ProfileSyncService* sync_service = GetSyncService(0); + base::FilePath directory_path = sync_service->GetDirectoryPathForTest(); + ASSERT_TRUE(base::DirectoryExists(directory_path)); + sync_service->StopAndSuppress(); + sync_service->DisableForUser(); + + // Wait for StartupController::StartUp()'s tasks to finish. + base::RunLoop run_loop; + base::MessageLoop::current()->PostTask(FROM_HERE, run_loop.QuitClosure()); + run_loop.Run(); + // Wait for the directory deletion to finish. + base::MessageLoop* sync_loop = sync_service->GetSyncLoopForTest(); + ASSERT_TRUE(WaitForExistingTasksOnLoop(sync_loop)); + + ASSERT_FALSE(base::DirectoryExists(directory_path)); +} diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index dcc96d772ce1e..f08a99f481781 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn @@ -224,13 +224,7 @@ static_library("ui") { gypi_values.chrome_browser_ui_views_non_chromeos_sources, ".", "//chrome") } - if (is_mac) { - if (mac_views_browser) { - sources -= [ "cocoa/browser_window_factory_cocoa.mm" ] - } else { - sources -= [ "views/frame/browser_window_factory.cc" ] - } - } else { + if (!is_mac) { sources += rebase_path( gypi_values.chrome_browser_ui_views_non_mac_sources, ".", "//chrome") diff --git a/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc b/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc index 858ae1932f9fe..baf38d92a731c 100644 --- a/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc +++ b/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc @@ -91,7 +91,9 @@ void AutofillPopupViewAndroid::UpdateBoundsAndRedrawPopup() { void AutofillPopupViewAndroid::SuggestionSelected(JNIEnv* env, jobject obj, jint list_index) { - controller_->AcceptSuggestion(list_index); + // Race: Hide() may have already run. + if (controller_) + controller_->AcceptSuggestion(list_index); } void AutofillPopupViewAndroid::PopupDismissed(JNIEnv* env, jobject obj) { diff --git a/chrome/browser/ui/android/tab_model/tab_model.h b/chrome/browser/ui/android/tab_model/tab_model.h index f6678d52346cd..0125f978e167d 100644 --- a/chrome/browser/ui/android/tab_model/tab_model.h +++ b/chrome/browser/ui/android/tab_model/tab_model.h @@ -38,6 +38,7 @@ class TabModel : public content::NotificationObserver { virtual int GetTabCount() const = 0; virtual int GetActiveIndex() const = 0; virtual content::WebContents* GetWebContentsAt(int index) const = 0; + // This will return NULL if the tab has not yet been initialized. virtual TabAndroid* GetTabAt(int index) const = 0; virtual void SetActiveIndex(int index) = 0; diff --git a/chrome/browser/ui/android/tab_model/tab_model_list.cc b/chrome/browser/ui/android/tab_model/tab_model_list.cc index 42e24ec2c92c2..04985b715bdba 100644 --- a/chrome/browser/ui/android/tab_model/tab_model_list.cc +++ b/chrome/browser/ui/android/tab_model/tab_model_list.cc @@ -52,8 +52,7 @@ TabModel* TabModelList::GetTabModelForWebContents( i != TabModelList::end(); ++i) { TabModel* model = *i; for (int index = 0; index < model->GetTabCount(); index++) { - TabAndroid* tab = model->GetTabAt(index); - if (web_contents == tab->web_contents()) + if (web_contents == model->GetWebContentsAt(index)) return model; } } diff --git a/chrome/browser/ui/android/tab_model/tab_model_list_unittest.cc b/chrome/browser/ui/android/tab_model/tab_model_list_unittest.cc new file mode 100644 index 0000000000000..1fb6b4b0fe93c --- /dev/null +++ b/chrome/browser/ui/android/tab_model/tab_model_list_unittest.cc @@ -0,0 +1,56 @@ +// 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 "chrome/browser/ui/android/tab_model/tab_model.h" +#include "chrome/browser/ui/android/tab_model/tab_model_list.h" +#include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "chrome/test/base/testing_profile.h" +#include "content/public/browser/web_contents.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { +class TabModelListTest : public ChromeRenderViewHostTestHarness {}; +} // namespace + +class TestTabModel : public TabModel { + public: + explicit TestTabModel(Profile* profile) : TabModel(profile), tab_count_(0) {} + + virtual int GetTabCount() const override { return tab_count_; } + virtual int GetActiveIndex() const override { return 0; } + virtual content::WebContents* GetWebContentsAt(int index) const override { + return nullptr; + } + virtual void CreateTab(content::WebContents* web_contents, + int parent_tab_id) override {} + virtual content::WebContents* CreateNewTabForDevTools( + const GURL& url) override { + return nullptr; + } + virtual bool IsSessionRestoreInProgress() const override { return false; } + virtual TabAndroid* GetTabAt(int index) const override { return nullptr; } + virtual void SetActiveIndex(int index) override {} + virtual void CloseTabAt(int index) override {} + + // A fake value for the current number of tabs. + int tab_count_; +}; + +// Regression test for http://crbug.com/432685. +TEST_F(TabModelListTest, TestGetTabModelForWebContents) { + TestTabModel tab_model(profile()); + TabModelList::AddTabModel(&tab_model); + + scoped_ptr contents(CreateTestWebContents()); + + // Should not crash when there are no tabs. + EXPECT_EQ(NULL, TabModelList::GetTabModelForWebContents(contents.get())); + + // Should not crash when there is an uninitialized tab, i.e. when + // TabModel::GetTabAt returns NULL. + tab_model.tab_count_ = 1; + EXPECT_EQ(NULL, TabModelList::GetTabModelForWebContents(contents.get())); + + TabModelList::RemoveTabModel(&tab_model); +} diff --git a/chrome/browser/ui/android/website_settings_popup_android.cc b/chrome/browser/ui/android/website_settings_popup_android.cc index dcece726260d5..f26ae56d999d9 100644 --- a/chrome/browser/ui/android/website_settings_popup_android.cc +++ b/chrome/browser/ui/android/website_settings_popup_android.cc @@ -104,7 +104,7 @@ void WebsiteSettingsPopupAndroid::SetPermissionInfo( std::vector permissions_to_display; permissions_to_display.push_back(CONTENT_SETTINGS_TYPE_GEOLOCATION); permissions_to_display.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM); - permissions_to_display.push_back(CONTENT_SETTINGS_TYPE_NOTIFICATIONS); + permissions_to_display.push_back(CONTENT_SETTINGS_TYPE_PUSH_MESSAGING); permissions_to_display.push_back(CONTENT_SETTINGS_TYPE_IMAGES); permissions_to_display.push_back(CONTENT_SETTINGS_TYPE_JAVASCRIPT); permissions_to_display.push_back(CONTENT_SETTINGS_TYPE_POPUPS); diff --git a/chrome/browser/ui/ash/launcher/app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/app_window_launcher_controller.cc index 9113e3b87f2b9..f07f122c61831 100644 --- a/chrome/browser/ui/ash/launcher/app_window_launcher_controller.cc +++ b/chrome/browser/ui/ash/launcher/app_window_launcher_controller.cc @@ -99,7 +99,8 @@ void AppWindowLauncherController::OnAppWindowIconChanged( app_window->app_icon().AsImageSkia()); } -void AppWindowLauncherController::OnAppWindowShown(AppWindow* app_window) { +void AppWindowLauncherController::OnAppWindowShown(AppWindow* app_window, + bool was_hidden) { aura::Window* window = app_window->GetNativeWindow(); if (!ControlsWindow(window)) return; diff --git a/chrome/browser/ui/ash/launcher/app_window_launcher_controller.h b/chrome/browser/ui/ash/launcher/app_window_launcher_controller.h index 8f2ca87ab6953..4ff452ee8cd88 100644 --- a/chrome/browser/ui/ash/launcher/app_window_launcher_controller.h +++ b/chrome/browser/ui/ash/launcher/app_window_launcher_controller.h @@ -51,7 +51,8 @@ class AppWindowLauncherController // Overridden from AppWindowRegistry::Observer: void OnAppWindowIconChanged(extensions::AppWindow* app_window) override; - void OnAppWindowShown(extensions::AppWindow* app_window) override; + void OnAppWindowShown(extensions::AppWindow* app_window, + bool was_hidden) override; void OnAppWindowHidden(extensions::AppWindow* app_window) override; // Overriden from aura::WindowObserver: diff --git a/chrome/browser/ui/ash/launcher/multi_profile_app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/multi_profile_app_window_launcher_controller.cc index 95c6f419734ea..00e8c7379ed6a 100644 --- a/chrome/browser/ui/ash/launcher/multi_profile_app_window_launcher_controller.cc +++ b/chrome/browser/ui/ash/launcher/multi_profile_app_window_launcher_controller.cc @@ -91,7 +91,8 @@ void MultiProfileAppWindowLauncherController::OnAppWindowAdded( } void MultiProfileAppWindowLauncherController::OnAppWindowShown( - extensions::AppWindow* app_window) { + extensions::AppWindow* app_window, + bool was_hidden) { if (!ControlsWindow(app_window->GetNativeWindow())) return; diff --git a/chrome/browser/ui/ash/launcher/multi_profile_app_window_launcher_controller.h b/chrome/browser/ui/ash/launcher/multi_profile_app_window_launcher_controller.h index 9e309060a6d18..d998ab64d6773 100644 --- a/chrome/browser/ui/ash/launcher/multi_profile_app_window_launcher_controller.h +++ b/chrome/browser/ui/ash/launcher/multi_profile_app_window_launcher_controller.h @@ -23,7 +23,8 @@ class MultiProfileAppWindowLauncherController // Overridden from AppWindowRegistry::Observer: void OnAppWindowAdded(extensions::AppWindow* app_window) override; void OnAppWindowRemoved(extensions::AppWindow* app_window) override; - void OnAppWindowShown(extensions::AppWindow* app_window) override; + void OnAppWindowShown(extensions::AppWindow* app_window, + bool was_hidden) override; void OnAppWindowHidden(extensions::AppWindow* app_window) override; private: diff --git a/chrome/browser/ui/browser_instant_controller.cc b/chrome/browser/ui/browser_instant_controller.cc index 73d08d516b077..c579176157be9 100644 --- a/chrome/browser/ui/browser_instant_controller.cc +++ b/chrome/browser/ui/browser_instant_controller.cc @@ -19,6 +19,7 @@ #include "chrome/browser/ui/search/search_model.h" #include "chrome/browser/ui/search/search_tab_helper.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/common/instant_types.h" #include "chrome/common/url_constants.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/user_metrics.h" @@ -73,6 +74,7 @@ bool BrowserInstantController::OpenInstant(WindowOpenDisposition disposition, const base::string16& search_terms = chrome::ExtractSearchTermsFromURL(profile(), url); + EmbeddedSearchRequestParams request_params(url); if (search_terms.empty()) return false; @@ -82,7 +84,7 @@ bool BrowserInstantController::OpenInstant(WindowOpenDisposition disposition, if (prerenderer->CanCommitQuery(GetActiveWebContents(), search_terms)) { // Submit query to render the prefetched results. Browser will swap the // prerendered contents with the active tab contents. - prerenderer->Commit(search_terms); + prerenderer->Commit(search_terms, request_params); return false; } else { prerenderer->Cancel(); @@ -93,8 +95,7 @@ bool BrowserInstantController::OpenInstant(WindowOpenDisposition disposition, // InstantController. if (!chrome::IsQueryExtractionAllowedForURL(profile(), url)) return false; - - return instant_.SubmitQuery(search_terms); + return instant_.SubmitQuery(search_terms, request_params); } Profile* BrowserInstantController::profile() const { diff --git a/chrome/browser/ui/cocoa/browser_window_factory_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_factory.mm similarity index 100% rename from chrome/browser/ui/cocoa/browser_window_factory_cocoa.mm rename to chrome/browser/ui/cocoa/browser_window_factory.mm diff --git a/chrome/browser/ui/extensions/extension_action_view_controller.cc b/chrome/browser/ui/extensions/extension_action_view_controller.cc index 82a28d508a358..5ee63c81a9bc3 100644 --- a/chrome/browser/ui/extensions/extension_action_view_controller.cc +++ b/chrome/browser/ui/extensions/extension_action_view_controller.cc @@ -16,6 +16,7 @@ #include "chrome/browser/ui/extensions/extension_action_platform_delegate.h" #include "chrome/browser/ui/toolbar/toolbar_action_view_delegate.h" #include "chrome/common/extensions/api/extension_action/action_info.h" +#include "extensions/browser/extension_registry.h" #include "extensions/common/extension.h" #include "extensions/common/manifest_constants.h" #include "ui/gfx/image/image_skia.h" @@ -34,7 +35,9 @@ ExtensionActionViewController::ExtensionActionViewController( view_delegate_(nullptr), platform_delegate_(ExtensionActionPlatformDelegate::Create(this)), icon_factory_(browser->profile(), extension, extension_action, this), - icon_observer_(nullptr) { + icon_observer_(nullptr), + extension_registry_( + extensions::ExtensionRegistry::Get(browser_->profile())) { DCHECK(extension_action); DCHECK(extension_action->action_type() == ActionInfo::TYPE_PAGE || extension_action->action_type() == ActionInfo::TYPE_BROWSER); @@ -56,10 +59,16 @@ void ExtensionActionViewController::SetDelegate( gfx::Image ExtensionActionViewController::GetIcon( content::WebContents* web_contents) { + if (!ExtensionIsValid()) + return gfx::Image(); + return icon_factory_.GetIcon(SessionTabHelper::IdForTab(web_contents)); } gfx::ImageSkia ExtensionActionViewController::GetIconWithBadge() { + if (!ExtensionIsValid()) + return gfx::ImageSkia(); + content::WebContents* web_contents = view_delegate_->GetCurrentWebContents(); gfx::Size spacing(0, 3); gfx::ImageSkia icon = *GetIcon(web_contents).ToImageSkia(); @@ -70,11 +79,17 @@ gfx::ImageSkia ExtensionActionViewController::GetIconWithBadge() { } base::string16 ExtensionActionViewController::GetActionName() const { + if (!ExtensionIsValid()) + return base::string16(); + return base::UTF8ToUTF16(extension_->name()); } base::string16 ExtensionActionViewController::GetAccessibleName( content::WebContents* web_contents) const { + if (!ExtensionIsValid()) + return base::string16(); + std::string title = extension_action()->GetTitle(SessionTabHelper::IdForTab(web_contents)); return base::UTF8ToUTF16(title.empty() ? extension()->name() : title); @@ -87,12 +102,18 @@ base::string16 ExtensionActionViewController::GetTooltip( bool ExtensionActionViewController::IsEnabled( content::WebContents* web_contents) const { + if (!ExtensionIsValid()) + return false; + return extension_action_->GetIsVisible( SessionTabHelper::IdForTab(web_contents)); } bool ExtensionActionViewController::HasPopup( content::WebContents* web_contents) const { + if (!ExtensionIsValid()) + return false; + int tab_id = SessionTabHelper::IdForTab(web_contents); return (tab_id < 0) ? false : extension_action_->HasPopup(tab_id); } @@ -120,6 +141,9 @@ bool ExtensionActionViewController::ExecuteAction(bool by_user) { bool ExtensionActionViewController::ExecuteAction(PopupShowAction show_action, bool grant_tab_permissions) { + if (!ExtensionIsValid()) + return false; + if (extensions::ExtensionActionAPI::Get(browser_->profile()) ->ExecuteExtensionAction( extension_, browser_, grant_tab_permissions) == @@ -137,12 +161,18 @@ void ExtensionActionViewController::PaintExtra( gfx::Canvas* canvas, const gfx::Rect& bounds, content::WebContents* web_contents) const { + if (!ExtensionIsValid()) + return; + int tab_id = SessionTabHelper::IdForTab(web_contents); if (tab_id >= 0) extension_action_->PaintBadge(canvas, bounds, tab_id); } void ExtensionActionViewController::RegisterCommand() { + if (!ExtensionIsValid()) + return; + platform_delegate_->RegisterCommand(); } @@ -157,9 +187,16 @@ void ExtensionActionViewController::OnIconUpdated() { view_delegate_->UpdateState(); } +bool ExtensionActionViewController::ExtensionIsValid() const { + return extension_registry_->enabled_extensions().Contains(extension_->id()); +} + bool ExtensionActionViewController::GetExtensionCommand( extensions::Command* command) { DCHECK(command); + if (!ExtensionIsValid()) + return false; + CommandService* command_service = CommandService::Get(browser_->profile()); if (extension_action_->action_type() == ActionInfo::TYPE_PAGE) { return command_service->GetPageActionCommand( @@ -173,6 +210,9 @@ bool ExtensionActionViewController::ShowPopupWithUrl( PopupShowAction show_action, const GURL& popup_url, bool grant_tab_permissions) { + if (!ExtensionIsValid()) + return false; + bool already_showing = platform_delegate_->IsShowingPopup(); // Always hide the current popup, even if it's not owned by this extension. diff --git a/chrome/browser/ui/extensions/extension_action_view_controller.h b/chrome/browser/ui/extensions/extension_action_view_controller.h index 77ae2f58bfabb..e7033100ff49d 100644 --- a/chrome/browser/ui/extensions/extension_action_view_controller.h +++ b/chrome/browser/ui/extensions/extension_action_view_controller.h @@ -18,10 +18,14 @@ class GURL; namespace extensions { class Command; class Extension; +class ExtensionRegistry; } // The platform-independent controller for an ExtensionAction that is shown on // the toolbar (such as a page or browser action). +// Since this class doesn't own the extension or extension action in question, +// be sure to check for validity using ExtensionIsValid() before using those +// members (see also comments above ExtensionIsValid()). class ExtensionActionViewController : public ToolbarActionViewController, public ExtensionActionIconFactory::Observer, @@ -77,6 +81,12 @@ class ExtensionActionViewController // ExtensionActionIconFactory::Observer: void OnIconUpdated() override; + // Checks if the associated |extension| is still valid by checking its + // status in the registry. Since the OnExtensionUnloaded() notifications are + // not in a deterministic order, it's possible that the view tries to refresh + // itself before we're notified to remove it. + bool ExtensionIsValid() const; + // Executes the extension action with |show_action|. If // |grant_tab_permissions| is true, this will grant the extension active tab // permissions. Only do this if this was done through a user action (and not @@ -118,6 +128,9 @@ class ExtensionActionViewController // has been updated. ExtensionActionIconFactory::Observer* icon_observer_; + // The associated ExtensionRegistry; cached for quick checking. + extensions::ExtensionRegistry* extension_registry_; + DISALLOW_COPY_AND_ASSIGN(ExtensionActionViewController); }; diff --git a/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc b/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc index 1e1b433b9d7fc..dd596716f4b29 100644 --- a/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc +++ b/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc @@ -8,6 +8,7 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h" +#include "chrome/browser/ui/passwords/password_bubble_experiment.h" #include "chrome/grit/generated_resources.h" #include "components/password_manager/core/browser/password_store.h" #include "components/password_manager/core/common/password_manager_ui.h" @@ -33,6 +34,15 @@ int GetFieldWidth(FieldType type) { : kPasswordFieldSize); } +void RecordExperimentStatistics(content::WebContents* web_contents, + metrics_util::UIDismissalReason reason) { + if (!web_contents) + return; + Profile* profile = + Profile::FromBrowserContext(web_contents->GetBrowserContext()); + password_bubble_experiment::RecordBubbleClosed(profile->GetPrefs(), reason); +} + } // namespace ManagePasswordsBubbleModel::ManagePasswordsBubbleModel( @@ -109,15 +119,20 @@ void ManagePasswordsBubbleModel::OnBubbleHidden() { return; metrics_util::LogUIDismissalReason(dismissal_reason_); + // Other use cases have been reported in the callbacks like OnSaveClicked(). + if (dismissal_reason_ == metrics_util::NO_DIRECT_INTERACTION) + RecordExperimentStatistics(web_contents(), dismissal_reason_); } void ManagePasswordsBubbleModel::OnNopeClicked() { dismissal_reason_ = metrics_util::CLICKED_NOPE; + RecordExperimentStatistics(web_contents(), dismissal_reason_); state_ = password_manager::ui::PENDING_PASSWORD_STATE; } void ManagePasswordsBubbleModel::OnNeverForThisSiteClicked() { dismissal_reason_ = metrics_util::CLICKED_NEVER; + RecordExperimentStatistics(web_contents(), dismissal_reason_); ManagePasswordsUIController* manage_passwords_ui_controller = ManagePasswordsUIController::FromWebContents(web_contents()); manage_passwords_ui_controller->NeverSavePassword(); @@ -134,6 +149,7 @@ void ManagePasswordsBubbleModel::OnUnblacklistClicked() { void ManagePasswordsBubbleModel::OnSaveClicked() { dismissal_reason_ = metrics_util::CLICKED_SAVE; + RecordExperimentStatistics(web_contents(), dismissal_reason_); ManagePasswordsUIController* manage_passwords_ui_controller = ManagePasswordsUIController::FromWebContents(web_contents()); manage_passwords_ui_controller->SavePassword(); diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc index 039f589960253..4afd3205d9c9f 100644 --- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc +++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc @@ -15,6 +15,7 @@ #include "chrome/browser/ui/chrome_pages.h" #include "chrome/browser/ui/location_bar/location_bar.h" #include "chrome/browser/ui/passwords/manage_passwords_icon.h" +#include "chrome/browser/ui/passwords/password_bubble_experiment.h" #include "chrome/common/url_constants.h" #include "components/password_manager/core/browser/password_store.h" #include "content/public/browser/notification_service.h" @@ -268,6 +269,10 @@ void ManagePasswordsUIController::ShowBubbleWithoutUserInteraction() { Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); if (!browser || browser->toolbar_model()->input_in_progress()) return; + if (state_ == password_manager::ui::PENDING_PASSWORD_AND_BUBBLE_STATE && + !password_bubble_experiment::ShouldShowBubble( + browser->profile()->GetPrefs())) + return; CommandUpdater* updater = browser->command_controller()->command_updater(); updater->ExecuteCommand(IDC_MANAGE_PASSWORDS_FOR_PAGE); #endif diff --git a/chrome/browser/ui/passwords/password_bubble_experiment.cc b/chrome/browser/ui/passwords/password_bubble_experiment.cc new file mode 100644 index 0000000000000..276a038e6a4e2 --- /dev/null +++ b/chrome/browser/ui/passwords/password_bubble_experiment.cc @@ -0,0 +1,205 @@ +// 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 "chrome/browser/ui/passwords/password_bubble_experiment.h" + +#include "base/metrics/field_trial.h" +#include "base/prefs/pref_service.h" +#include "base/rand_util.h" +#include "base/strings/string_number_conversions.h" +#include "base/time/time.h" +#include "chrome/common/pref_names.h" +#include "components/pref_registry/pref_registry_syncable.h" +#include "components/variations/variations_associated_data.h" + +namespace password_bubble_experiment { +namespace { + +bool IsNegativeEvent(password_manager::metrics_util::UIDismissalReason reason) { + return (reason == password_manager::metrics_util::NO_DIRECT_INTERACTION || + reason == password_manager::metrics_util::CLICKED_NOPE || + reason == password_manager::metrics_util::CLICKED_NEVER); +} + +// "TimeSpan" experiment ----------------------------------------------------- + +bool ExtractTimeSpanParams(base::TimeDelta* time_delta, int* nopes_limit) { + std::map params; + bool retrieved = variations::GetVariationParams(kExperimentName, ¶ms); + if (!retrieved) + return false; + int days = 0; + if (!base::StringToInt(params[kParamTimeSpan], &days) || + !base::StringToInt(params[kParamTimeSpanNopeThreshold], nopes_limit)) + return false; + *time_delta = base::TimeDelta::FromDays(days); + return true; +} + +bool OverwriteTimeSpanPrefsIfNeeded(PrefService* prefs, + base::TimeDelta time_span) { + base::Time beginning = base::Time::FromInternalValue( + prefs->GetInt64(prefs::kPasswordBubbleTimeStamp)); + base::Time now = base::Time::Now(); + if (beginning + time_span < now) { + prefs->SetInt64(prefs::kPasswordBubbleTimeStamp, now.ToInternalValue()); + prefs->SetInteger(prefs::kPasswordBubbleNopesCount, 0); + return true; + } + return false; +} + +// If user dismisses the bubble >= kParamTimeSpanNopeThreshold times during +// kParamTimeSpan days then the bubble isn't shown until the end of this time +// span. +bool ShouldShowBubbleTimeSpanExperiment(PrefService* prefs) { + base::TimeDelta time_span; + int nopes_limit = 0; + if (!ExtractTimeSpanParams(&time_span, &nopes_limit)) { + VLOG(2) << "Can't read parameters for " + << kExperimentName << " experiment"; + return true; + } + // Check if the new time span has started. + if (OverwriteTimeSpanPrefsIfNeeded(prefs, time_span)) + return true; + int current_nopes = prefs->GetInteger(prefs::kPasswordBubbleNopesCount); + return current_nopes < nopes_limit; +} + +// Increase the "Nope" counter in prefs and start a new time span if needed. +void UpdateTimeSpanPrefs( + PrefService* prefs, + password_manager::metrics_util::UIDismissalReason reason) { + if (!IsNegativeEvent(reason)) + return; + base::TimeDelta time_span; + int nopes_limit = 0; + if (!ExtractTimeSpanParams(&time_span, &nopes_limit)) { + VLOG(2) << "Can't read parameters for " + << kExperimentName << " experiment"; + return; + } + OverwriteTimeSpanPrefsIfNeeded(prefs, time_span); + int current_nopes = prefs->GetInteger(prefs::kPasswordBubbleNopesCount); + prefs->SetInteger(prefs::kPasswordBubbleNopesCount, current_nopes + 1); +} + +// "Probability" experiment -------------------------------------------------- + +bool ExtractProbabilityParams(unsigned* history_length, unsigned* saves) { + std::map params; + bool retrieved = variations::GetVariationParams(kExperimentName, ¶ms); + if (!retrieved) + return false; + return base::StringToUint(params[kParamProbabilityInteractionsCount], + history_length) && + base::StringToUint(params[kParamProbabilityFakeSaves], saves); +} + +std::vector ReadInteractionHistory(PrefService* prefs) { + std::vector interactions; + const base::ListValue* list = + prefs->GetList(prefs::kPasswordBubbleLastInteractions); + if (!list) + return interactions; + for (const base::Value* value : *list) { + int out_value; + if (value->GetAsInteger(&out_value)) + interactions.push_back(out_value); + } + return interactions; +} + +// We keep the history of last kParamProbabilityInteractionsCount interactions +// with the bubble. We implicitly add kParamProbabilityFakeSaves "Save" clicks. +// If there are x "Save" clicks among those kParamProbabilityInteractionsCount +// then the bubble is shown with probability (x + kParamProbabilityFakeSaves)/ +// (kParamProbabilityInteractionsCount + kParamProbabilityFakeSaves). +bool ShouldShowBubbleProbabilityExperiment(PrefService* prefs) { + unsigned history_length = 0, fake_saves = 0; + if (!ExtractProbabilityParams(&history_length, &fake_saves)) { + VLOG(2) << "Can't read parameters for " + << kExperimentName << " experiment"; + return true; + } + std::vector interactions = ReadInteractionHistory(prefs); + unsigned real_saves = + std::count(interactions.begin(), interactions.end(), + password_manager::metrics_util::CLICKED_SAVE); + return (interactions.size() + fake_saves) * base::RandDouble() <= + real_saves + fake_saves; +} + +void UpdateProbabilityPrefs( + PrefService* prefs, + password_manager::metrics_util::UIDismissalReason reason) { + if (!IsNegativeEvent(reason) && + reason != password_manager::metrics_util::CLICKED_SAVE) + return; + unsigned history_length = 0, fake_saves = 0; + if (!ExtractProbabilityParams(&history_length, &fake_saves)) { + VLOG(2) << "Can't read parameters for " + << kExperimentName << " experiment"; + return; + } + std::vector interactions = ReadInteractionHistory(prefs); + interactions.push_back(reason); + size_t history_beginning = interactions.size() > history_length ? + interactions.size() - history_length : 0; + base::ListValue value; + for (size_t i = history_beginning; i < interactions.size(); ++i) + value.AppendInteger(interactions[i]); + prefs->Set(prefs::kPasswordBubbleLastInteractions, value); +} + +} // namespace + +const char kExperimentName[] = "PasswordBubbleAlgorithm"; +const char kGroupTimeSpanBased[] = "TimeSpan"; +const char kGroupProbabilityBased[] = "Probability"; +const char kParamProbabilityFakeSaves[] = "saves_count"; +const char kParamProbabilityInteractionsCount[] = "last_interactions_count"; +const char kParamTimeSpan[] = "time_span"; +const char kParamTimeSpanNopeThreshold[] = "nope_threshold"; + +void RegisterPrefs(user_prefs::PrefRegistrySyncable* registry) { + registry->RegisterInt64Pref( + prefs::kPasswordBubbleTimeStamp, + 0, + user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); + registry->RegisterIntegerPref( + prefs::kPasswordBubbleNopesCount, + 0, + user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); + registry->RegisterListPref( + prefs::kPasswordBubbleLastInteractions, + user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); +} + +bool ShouldShowBubble(PrefService* prefs) { + if (!base::FieldTrialList::TrialExists(kExperimentName)) + return true; + std::string group_name = + base::FieldTrialList::FindFullName(kExperimentName); + + if (group_name == kGroupTimeSpanBased) { + return ShouldShowBubbleTimeSpanExperiment(prefs); + } + if (group_name == kGroupProbabilityBased) { + return ShouldShowBubbleProbabilityExperiment(prefs); + } + + // The "Show Always" should be the default case. + return true; +} + +void RecordBubbleClosed( + PrefService* prefs, + password_manager::metrics_util::UIDismissalReason reason) { + UpdateTimeSpanPrefs(prefs, reason); + UpdateProbabilityPrefs(prefs, reason); +} + +} // namespace password_bubble_experiment diff --git a/chrome/browser/ui/passwords/password_bubble_experiment.h b/chrome/browser/ui/passwords/password_bubble_experiment.h new file mode 100644 index 0000000000000..9c4d30272df0f --- /dev/null +++ b/chrome/browser/ui/passwords/password_bubble_experiment.h @@ -0,0 +1,57 @@ +// 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 CHROME_BROWSER_UI_PASSWORDS_PASSWORD_BUBBLE_EXPERIMENT_H_ +#define CHROME_BROWSER_UI_PASSWORDS_PASSWORD_BUBBLE_EXPERIMENT_H_ + +#include "base/macros.h" +#include "components/password_manager/core/browser/password_manager_metrics_util.h" + +namespace user_prefs { +class PrefRegistrySyncable; +} + +class PrefService; + +// These functions handle the algorithms according to which the "Save password?" +// bubble is shown to user. +namespace password_bubble_experiment { + +void RegisterPrefs(user_prefs::PrefRegistrySyncable* registry); + +// The decision is made based on the "PasswordBubbleAlgorithm" finch experiment. +// The default value is true. +// It should be called before showing the "Save Password?" dialog. +bool ShouldShowBubble(PrefService* prefs); + +// Should be called when user dismisses the "Save Password?" dialog. It stores +// the statistics about interactions with the bubble. +void RecordBubbleClosed( + PrefService* prefs, + password_manager::metrics_util::UIDismissalReason reason); + +// The name of the finch experiment controlling the algorithm. +extern const char kExperimentName[]; + +// The group name for the time based algorithm. +extern const char kGroupTimeSpanBased[]; + +// The group name for the probability algorithm. +extern const char kGroupProbabilityBased[]; + +// For "Probability" group. The additional "Saves" to be added to the model. +extern const char kParamProbabilityFakeSaves[]; + +// For "Probability" group. The interaction history length. +extern const char kParamProbabilityInteractionsCount[]; + +// For "TimeSpan" group. The time span until the nope counter is zeroed. +extern const char kParamTimeSpan[]; + +// For "TimeSpan" group. The nopes threshold. +extern const char kParamTimeSpanNopeThreshold[]; + +} // namespace password_bubble_experiment + +#endif // CHROME_BROWSER_UI_PASSWORDS_PASSWORD_BUBBLE_EXPERIMENT_H_ diff --git a/chrome/browser/ui/passwords/password_bubble_experiment_unittest.cc b/chrome/browser/ui/passwords/password_bubble_experiment_unittest.cc new file mode 100644 index 0000000000000..96265b5b92998 --- /dev/null +++ b/chrome/browser/ui/passwords/password_bubble_experiment_unittest.cc @@ -0,0 +1,139 @@ +// 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 "chrome/browser/ui/passwords/password_bubble_experiment.h" + +#include "base/files/scoped_temp_dir.h" +#include "base/metrics/field_trial.h" +#include "base/prefs/pref_service.h" +#include "base/strings/string_number_conversions.h" +#include "chrome/common/pref_names.h" +#include "chrome/test/base/testing_profile.h" +#include "components/variations/entropy_provider.h" +#include "components/variations/variations_associated_data.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +const int kTimeSpanDays = 2; +const int kTimeSpanThreshold = 3; +const int kProbabilityFakeSaves = 0; +const int kProbabilityHistory = 10; + +void SetupTimeSpanExperiment() { + ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial( + password_bubble_experiment::kExperimentName, + password_bubble_experiment::kGroupTimeSpanBased)); + std::map params; + params[password_bubble_experiment::kParamTimeSpan] = + base::IntToString(kTimeSpanDays); + params[password_bubble_experiment::kParamTimeSpanNopeThreshold] = + base::IntToString(kTimeSpanThreshold); + ASSERT_TRUE(variations::AssociateVariationParams( + password_bubble_experiment::kExperimentName, + password_bubble_experiment::kGroupTimeSpanBased, + params)); +} + +void SetupProbabilityExperiment() { + ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial( + password_bubble_experiment::kExperimentName, + password_bubble_experiment::kGroupProbabilityBased)); + std::map params; + params[password_bubble_experiment::kParamProbabilityFakeSaves] = + base::IntToString(kProbabilityFakeSaves); + params[password_bubble_experiment::kParamProbabilityInteractionsCount] = + base::IntToString(kProbabilityHistory); + ASSERT_TRUE(variations::AssociateVariationParams( + password_bubble_experiment::kExperimentName, + password_bubble_experiment::kGroupProbabilityBased, + params)); +} + +} // namespace + +class PasswordBubbleExperimentTest : public testing::Test { + public: + void SetUp() override { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + profile_.reset(new TestingProfile(temp_dir_.path())); + + field_trial_list_.reset(new base::FieldTrialList( + new metrics::SHA1EntropyProvider("foo"))); + variations::testing::ClearAllVariationParams(); + } + + PrefService* prefs() { return profile_->GetPrefs(); } + + private: + base::ScopedTempDir temp_dir_; + scoped_ptr profile_; + scoped_ptr field_trial_list_; +}; + +TEST_F(PasswordBubbleExperimentTest, TimeSpan) { + SetupTimeSpanExperiment(); + + EXPECT_TRUE(password_bubble_experiment::ShouldShowBubble(prefs())); + // Don't save password enough times. + for (int i = 0; i < kTimeSpanThreshold; ++i) { + password_manager::metrics_util::UIDismissalReason reason = i % 2 ? + password_manager::metrics_util::NO_DIRECT_INTERACTION : + password_manager::metrics_util::CLICKED_NOPE; + password_bubble_experiment::RecordBubbleClosed(prefs(), reason); + } + EXPECT_FALSE(password_bubble_experiment::ShouldShowBubble(prefs())); + + // Save password many times. It doesn't bring the bubble back while the time + // span isn't over. + for (int i = 0; i < 2*kTimeSpanThreshold; ++i) { + password_bubble_experiment::RecordBubbleClosed( + prefs(), + password_manager::metrics_util::CLICKED_SAVE); + } + EXPECT_FALSE(password_bubble_experiment::ShouldShowBubble(prefs())); +} + +TEST_F(PasswordBubbleExperimentTest, TimeSpanOver) { + SetupTimeSpanExperiment(); + + base::Time past_interval = + base::Time::Now() - base::TimeDelta::FromDays(kTimeSpanDays + 1); + prefs()->SetInt64(prefs::kPasswordBubbleTimeStamp, + past_interval.ToInternalValue()); + prefs()->SetInteger(prefs::kPasswordBubbleNopesCount, kTimeSpanThreshold); + // The time span is over. The bubble should be shown. + EXPECT_TRUE(password_bubble_experiment::ShouldShowBubble(prefs())); + EXPECT_EQ(0, prefs()->GetInteger(prefs::kPasswordBubbleNopesCount)); + + // Set the old time span again and record "Nope". The counter restarts from 0. + prefs()->SetInt64(prefs::kPasswordBubbleTimeStamp, + past_interval.ToInternalValue()); + password_bubble_experiment::RecordBubbleClosed( + prefs(), password_manager::metrics_util::CLICKED_NOPE); + EXPECT_TRUE(password_bubble_experiment::ShouldShowBubble(prefs())); + EXPECT_EQ(1, prefs()->GetInteger(prefs::kPasswordBubbleNopesCount)); +} + +TEST_F(PasswordBubbleExperimentTest, Probability) { + SetupProbabilityExperiment(); + + EXPECT_TRUE(password_bubble_experiment::ShouldShowBubble(prefs())); + // Don't save password enough times. + for (int i = 0; i < kProbabilityHistory; ++i) { + password_manager::metrics_util::UIDismissalReason reason = i % 2 ? + password_manager::metrics_util::NO_DIRECT_INTERACTION : + password_manager::metrics_util::CLICKED_NOPE; + password_bubble_experiment::RecordBubbleClosed(prefs(), reason); + } + EXPECT_FALSE(password_bubble_experiment::ShouldShowBubble(prefs())); + + // Save password enough times. + for (int i = 0; i < kProbabilityHistory; ++i) { + password_bubble_experiment::RecordBubbleClosed( + prefs(), + password_manager::metrics_util::CLICKED_SAVE); + } + EXPECT_TRUE(password_bubble_experiment::ShouldShowBubble(prefs())); +} diff --git a/chrome/browser/ui/search/instant_controller.cc b/chrome/browser/ui/search/instant_controller.cc index c6edfdd266aeb..c0be4f5ff3c21 100644 --- a/chrome/browser/ui/search/instant_controller.cc +++ b/chrome/browser/ui/search/instant_controller.cc @@ -78,13 +78,14 @@ InstantController::InstantController(BrowserInstantController* browser) InstantController::~InstantController() { } -bool InstantController::SubmitQuery(const base::string16& search_terms) { +bool InstantController::SubmitQuery(const base::string16& search_terms, + const EmbeddedSearchRequestParams& params) { if (instant_tab_ && instant_tab_->supports_instant() && search_mode_.is_origin_search()) { // Use |instant_tab_| to run the query if we're already on a search results // page. (NOTE: in particular, we do not send the query to NTPs.) SearchTabHelper::FromWebContents(instant_tab_->web_contents())->Submit( - search_terms); + search_terms, params); instant_tab_->web_contents()->Focus(); EnsureSearchTermsAreSet(instant_tab_->web_contents(), search_terms); return true; diff --git a/chrome/browser/ui/search/instant_controller.h b/chrome/browser/ui/search/instant_controller.h index d7b7b09013e54..44ccf7710e69d 100644 --- a/chrome/browser/ui/search/instant_controller.h +++ b/chrome/browser/ui/search/instant_controller.h @@ -23,6 +23,7 @@ class GURL; class InstantService; class InstantTab; class Profile; +struct EmbeddedSearchRequestParams; namespace content { class WebContents; @@ -49,7 +50,8 @@ class InstantController : public InstantPage::Delegate { // Called if the browser is navigating to a search URL for |search_terms| with // search-term-replacement enabled. If |instant_tab_| can be used to process // the search, this does so and returns true. Else, returns false. - bool SubmitQuery(const base::string16& search_terms); + bool SubmitQuery(const base::string16& search_terms, + const EmbeddedSearchRequestParams& params); // The search mode in the active tab has changed. Bind |instant_tab_| if the // |new_mode| reflects an Instant search results page. diff --git a/chrome/browser/ui/search/instant_search_prerenderer.cc b/chrome/browser/ui/search/instant_search_prerenderer.cc index e7ed452e6028e..94b94deaf136c 100644 --- a/chrome/browser/ui/search/instant_search_prerenderer.cc +++ b/chrome/browser/ui/search/instant_search_prerenderer.cc @@ -100,10 +100,12 @@ void InstantSearchPrerenderer::Prerender(const InstantSuggestion& suggestion) { SetSuggestionToPrefetch(suggestion); } -void InstantSearchPrerenderer::Commit(const base::string16& query) { +void InstantSearchPrerenderer::Commit( + const base::string16& query, + const EmbeddedSearchRequestParams& params) { DCHECK(prerender_handle_); DCHECK(prerender_contents()); - SearchTabHelper::FromWebContents(prerender_contents())->Submit(query); + SearchTabHelper::FromWebContents(prerender_contents())->Submit(query, params); } bool InstantSearchPrerenderer::CanCommitQuery( diff --git a/chrome/browser/ui/search/instant_search_prerenderer.h b/chrome/browser/ui/search/instant_search_prerenderer.h index dba90417772e4..797bd57862278 100644 --- a/chrome/browser/ui/search/instant_search_prerenderer.h +++ b/chrome/browser/ui/search/instant_search_prerenderer.h @@ -61,7 +61,8 @@ class InstantSearchPrerenderer { // Tells the Instant search base page to render the search results for the // given |query|. - void Commit(const base::string16& query); + void Commit(const base::string16& query, + const EmbeddedSearchRequestParams& params); // Returns true if the prerendered page can be used to process the search for // the given |source|. diff --git a/chrome/browser/ui/search/instant_search_prerenderer_unittest.cc b/chrome/browser/ui/search/instant_search_prerenderer_unittest.cc index 8501ea4e90562..b708b85484ac7 100644 --- a/chrome/browser/ui/search/instant_search_prerenderer_unittest.cc +++ b/chrome/browser/ui/search/instant_search_prerenderer_unittest.cc @@ -21,8 +21,10 @@ #include "chrome/browser/search/instant_service.h" #include "chrome/browser/search/instant_unittest_base.h" #include "chrome/browser/search/search.h" +#include "chrome/browser/ui/browser_instant_controller.h" #include "chrome/browser/ui/search/search_tab_helper.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/common/instant_types.h" #include "chrome/common/render_messages.h" #include "components/omnibox/autocomplete_match.h" #include "content/public/browser/navigation_controller.h" @@ -295,7 +297,7 @@ TEST_F(InstantSearchPrerendererTest, CommitQuery) { base::string16 query = ASCIIToUTF16("flowers"); PrerenderSearchQuery(query); InstantSearchPrerenderer* prerenderer = GetInstantSearchPrerenderer(); - prerenderer->Commit(query); + prerenderer->Commit(query, EmbeddedSearchRequestParams()); EXPECT_TRUE(MessageWasSent(ChromeViewMsg_SearchBoxSubmit::ID)); } @@ -493,4 +495,30 @@ TEST_F(TestUsePrerenderPage, ExtractSearchTermsAndUsePrerenderPage) { EXPECT_EQ(GetPrerenderURL(), GetActiveWebContents()->GetURL()); EXPECT_EQ(static_cast(NULL), prerender_handle()); } + +TEST_F(TestUsePrerenderPage, SetEmbeddedSearchRequestParams) { + PrerenderSearchQuery(ASCIIToUTF16("foo")); + EXPECT_TRUE(browser()->instant_controller()); + + // Open a search results page. Query extraction flag is disabled in field + // trials. Search results page URL does not contain search terms replacement + // key. + GURL url("https://www.google.com/url?bar=foo&aqs=chrome...0&ie=utf-8&oq=f"); + browser()->instant_controller()->OpenInstant(CURRENT_TAB, url); + content::MockRenderProcessHost* process = + static_cast( + prerender_contents()->GetRenderViewHost()->GetProcess()); + const IPC::Message* message = process->sink().GetFirstMessageMatching( + ChromeViewMsg_SearchBoxSubmit::ID); + ASSERT_TRUE(message); + + // Verify the IPC message params. + Tuple2 params; + ChromeViewMsg_SearchBoxSubmit::Read(message, ¶ms); + EXPECT_EQ("foo", base::UTF16ToASCII(params.a)); + EXPECT_EQ("f", base::UTF16ToASCII(params.b.original_query)); + EXPECT_EQ("utf-8", base::UTF16ToASCII(params.b.input_encoding)); + EXPECT_EQ("", base::UTF16ToASCII(params.b.rlz_parameter_value)); + EXPECT_EQ("chrome...0", base::UTF16ToASCII(params.b.assisted_query_stats)); +} #endif diff --git a/chrome/browser/ui/search/search_ipc_router.cc b/chrome/browser/ui/search/search_ipc_router.cc index c81a1e99229a4..9e592c5fc8297 100644 --- a/chrome/browser/ui/search/search_ipc_router.cc +++ b/chrome/browser/ui/search/search_ipc_router.cc @@ -136,11 +136,12 @@ void SearchIPCRouter::ToggleVoiceSearch() { Send(new ChromeViewMsg_SearchBoxToggleVoiceSearch(routing_id())); } -void SearchIPCRouter::Submit(const base::string16& text) { +void SearchIPCRouter::Submit(const base::string16& text, + const EmbeddedSearchRequestParams& params) { if (!policy_->ShouldSubmitQuery()) return; - Send(new ChromeViewMsg_SearchBoxSubmit(routing_id(), text)); + Send(new ChromeViewMsg_SearchBoxSubmit(routing_id(), text, params)); } void SearchIPCRouter::OnTabActivated() { diff --git a/chrome/browser/ui/search/search_ipc_router.h b/chrome/browser/ui/search/search_ipc_router.h index b2af4efc6c9a7..e5ab6626535ff 100644 --- a/chrome/browser/ui/search/search_ipc_router.h +++ b/chrome/browser/ui/search/search_ipc_router.h @@ -160,7 +160,8 @@ class SearchIPCRouter : public content::WebContentsObserver { void ToggleVoiceSearch(); // Tells the page that the user pressed Enter in the omnibox. - void Submit(const base::string16& text); + void Submit(const base::string16& text, + const EmbeddedSearchRequestParams& params); // Called when the tab corresponding to |this| instance is activated. void OnTabActivated(); diff --git a/chrome/browser/ui/search/search_ipc_router_unittest.cc b/chrome/browser/ui/search/search_ipc_router_unittest.cc index 2d33e1f3afb94..d4836c640f4de 100644 --- a/chrome/browser/ui/search/search_ipc_router_unittest.cc +++ b/chrome/browser/ui/search/search_ipc_router_unittest.cc @@ -871,7 +871,7 @@ TEST_F(SearchIPCRouterTest, SendSubmitMsg) { .WillOnce(testing::Return(true)); process()->sink().ClearMessages(); - GetSearchIPCRouter().Submit(base::string16()); + GetSearchIPCRouter().Submit(base::string16(), EmbeddedSearchRequestParams()); EXPECT_TRUE(MessageWasSent(ChromeViewMsg_SearchBoxSubmit::ID)); } @@ -883,7 +883,7 @@ TEST_F(SearchIPCRouterTest, DoNotSendSubmitMsg) { .WillOnce(testing::Return(false)); process()->sink().ClearMessages(); - GetSearchIPCRouter().Submit(base::string16()); + GetSearchIPCRouter().Submit(base::string16(), EmbeddedSearchRequestParams()); EXPECT_FALSE(MessageWasSent(ChromeViewMsg_SearchBoxSubmit::ID)); } diff --git a/chrome/browser/ui/search/search_tab_helper.cc b/chrome/browser/ui/search/search_tab_helper.cc index f2c34e773db55..1ed4f538a04f5 100644 --- a/chrome/browser/ui/search/search_tab_helper.cc +++ b/chrome/browser/ui/search/search_tab_helper.cc @@ -255,8 +255,9 @@ void SearchTabHelper::SetSuggestionToPrefetch( ipc_router_.SetSuggestionToPrefetch(suggestion); } -void SearchTabHelper::Submit(const base::string16& text) { - ipc_router_.Submit(text); +void SearchTabHelper::Submit(const base::string16& text, + const EmbeddedSearchRequestParams& params) { + ipc_router_.Submit(text, params); } void SearchTabHelper::OnTabActivated() { diff --git a/chrome/browser/ui/search/search_tab_helper.h b/chrome/browser/ui/search/search_tab_helper.h index 5b5f460fcde3c..061e0980f1e20 100644 --- a/chrome/browser/ui/search/search_tab_helper.h +++ b/chrome/browser/ui/search/search_tab_helper.h @@ -80,7 +80,8 @@ class SearchTabHelper : public content::WebContentsObserver, void SetSuggestionToPrefetch(const InstantSuggestion& suggestion); // Tells the page that the user pressed Enter in the omnibox. - void Submit(const base::string16& text); + void Submit(const base::string16& text, + const EmbeddedSearchRequestParams& params); // Called when the tab corresponding to |this| instance is activated. void OnTabActivated(); diff --git a/chrome/browser/ui/settings_window_manager.cc b/chrome/browser/ui/settings_window_manager.cc index c60d5aed54553..5e4954b8cae94 100644 --- a/chrome/browser/ui/settings_window_manager.cc +++ b/chrome/browser/ui/settings_window_manager.cc @@ -35,6 +35,11 @@ void SettingsWindowManager::RemoveObserver( void SettingsWindowManager::ShowChromePageForProfile(Profile* profile, const GURL& gurl) { + // Use the original (non off-the-record) profile for settings unless + // this is a guest session. + if (!profile->IsGuestSession() && profile->IsOffTheRecord()) + profile = profile->GetOriginalProfile(); + // Look for an existing browser window. Browser* browser = FindBrowserForProfile(profile); if (browser) { @@ -62,6 +67,7 @@ void SettingsWindowManager::ShowChromePageForProfile(Profile* profile, params.path_behavior = NavigateParams::IGNORE_AND_NAVIGATE; chrome::Navigate(¶ms); settings_session_map_[profile] = params.browser->session_id().id(); + DCHECK(params.browser->is_trusted_source()); FOR_EACH_OBSERVER(SettingsWindowManagerObserver, observers_, OnNewSettingsWindow(params.browser)); diff --git a/chrome/browser/ui/views/extensions/extension_action_platform_delegate_views.cc b/chrome/browser/ui/views/extensions/extension_action_platform_delegate_views.cc index c9bac7c563f15..33aba19f72f84 100644 --- a/chrome/browser/ui/views/extensions/extension_action_platform_delegate_views.cc +++ b/chrome/browser/ui/views/extensions/extension_action_platform_delegate_views.cc @@ -119,8 +119,9 @@ bool ExtensionActionPlatformDelegateViews::ShowPopupWithUrl( ExtensionActionViewController::PopupShowAction show_action, const GURL& popup_url, bool grant_tab_permissions) { - views::BubbleBorder::Arrow arrow = base::i18n::IsRTL() ? - views::BubbleBorder::TOP_LEFT : views::BubbleBorder::TOP_RIGHT; + // TOP_RIGHT is correct for both RTL and LTR, because the views platform + // performs the flipping in RTL cases. + views::BubbleBorder::Arrow arrow = views::BubbleBorder::TOP_RIGHT; views::View* reference_view = GetDelegateViews()->GetReferenceViewForPopup(); diff --git a/chrome/browser/ui/views/frame/browser_command_handler_x11.cc b/chrome/browser/ui/views/frame/browser_command_handler_x11.cc index 4afe77a6d95d8..ce37fcc47799a 100644 --- a/chrome/browser/ui/views/frame/browser_command_handler_x11.cc +++ b/chrome/browser/ui/views/frame/browser_command_handler_x11.cc @@ -8,26 +8,15 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/browser/ui/views/frame/browser_view.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/web_contents.h" -#include "ui/aura/window.h" #include "ui/events/event.h" #include "ui/events/event_utils.h" -BrowserCommandHandlerX11::BrowserCommandHandlerX11(BrowserView* browser_view) - : browser_view_(browser_view) { - aura::Window* window = browser_view_->frame()->GetNativeWindow(); - DCHECK(window); - if (window) - window->AddPreTargetHandler(this); -} +BrowserCommandHandlerX11::BrowserCommandHandlerX11(Browser* browser) + : browser_(browser) {} -BrowserCommandHandlerX11::~BrowserCommandHandlerX11() { - aura::Window* window = browser_view_->frame()->GetNativeWindow(); - if (window) - window->RemovePreTargetHandler(this); -} +BrowserCommandHandlerX11::~BrowserCommandHandlerX11() {} void BrowserCommandHandlerX11::OnMouseEvent(ui::MouseEvent* event) { if (event->type() != ui::ET_MOUSE_PRESSED) @@ -43,7 +32,7 @@ void BrowserCommandHandlerX11::OnMouseEvent(ui::MouseEvent* event) { const int kForwardMouseButton = 9; if (button == kBackMouseButton || button == kForwardMouseButton) { content::WebContents* contents = - browser_view_->browser()->tab_strip_model()->GetActiveWebContents(); + browser_->tab_strip_model()->GetActiveWebContents(); if (!contents) return; content::NavigationController& controller = contents->GetController(); diff --git a/chrome/browser/ui/views/frame/browser_command_handler_x11.h b/chrome/browser/ui/views/frame/browser_command_handler_x11.h index fdc9294c41eb5..0542401e8eeb6 100644 --- a/chrome/browser/ui/views/frame/browser_command_handler_x11.h +++ b/chrome/browser/ui/views/frame/browser_command_handler_x11.h @@ -6,20 +6,19 @@ #define CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_COMMAND_HANDLER_X11_H_ #include "ui/events/event_handler.h" -#include "ui/gfx/native_widget_types.h" -class BrowserView; +class Browser; class BrowserCommandHandlerX11 : public ui::EventHandler { public: - explicit BrowserCommandHandlerX11(BrowserView* browser_view); + explicit BrowserCommandHandlerX11(Browser* browser); ~BrowserCommandHandlerX11() override; private: // ui::EventHandler: void OnMouseEvent(ui::MouseEvent* event) override; - BrowserView* browser_view_; + Browser* browser_; DISALLOW_COPY_AND_ASSIGN(BrowserCommandHandlerX11); }; diff --git a/chrome/browser/ui/views/frame/browser_frame.cc b/chrome/browser/ui/views/frame/browser_frame.cc index a4e9535344a6d..890d1de39f44d 100644 --- a/chrome/browser/ui/views/frame/browser_frame.cc +++ b/chrome/browser/ui/views/frame/browser_frame.cc @@ -4,11 +4,14 @@ #include "chrome/browser/ui/views/frame/browser_frame.h" +#include "ash/shell.h" +#include "base/command_line.h" #include "base/debug/leak_annotations.h" #include "base/i18n/rtl.h" #include "chrome/browser/app_mode/app_mode_utils.h" #include "chrome/browser/themes/theme_service.h" #include "chrome/browser/themes/theme_service_factory.h" +#include "chrome/browser/ui/ash/ash_util.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window_state.h" @@ -20,7 +23,11 @@ #include "chrome/browser/ui/views/frame/native_browser_frame_factory.h" #include "chrome/browser/ui/views/frame/system_menu_model_builder.h" #include "chrome/browser/ui/views/frame/top_container_view.h" +#include "chrome/browser/web_applications/web_app.h" +#include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" +#include "ui/aura/window.h" +#include "ui/aura/window_event_dispatcher.h" #include "ui/base/hit_test.h" #include "ui/base/theme_provider.h" #include "ui/events/event_handler.h" @@ -29,9 +36,12 @@ #include "ui/views/controls/menu/menu_runner.h" #include "ui/views/widget/native_widget.h" +#if defined(OS_LINUX) && !defined(OS_CHROMEOS) +#include "chrome/browser/shell_integration_linux.h" +#endif + #if defined(OS_CHROMEOS) #include "ash/session/session_state_delegate.h" -#include "ash/shell.h" #endif #if defined(USE_X11) @@ -52,9 +62,16 @@ BrowserFrame::BrowserFrame(BrowserView* browser_view) set_is_secondary_widget(false); // Don't focus anything on creation, selecting a tab will set the focus. set_focus_on_creation(false); + +#if defined(USE_X11) + browser_command_handler_.reset( + new BrowserCommandHandlerX11(browser_view_->browser())); +#endif } BrowserFrame::~BrowserFrame() { + if (browser_command_handler_ && GetNativeView()) + GetNativeView()->RemovePreTargetHandler(browser_command_handler_.get()); } // static @@ -73,8 +90,9 @@ void BrowserFrame::InitBrowserFrame() { native_browser_frame_ = NativeBrowserFrameFactory::CreateNativeBrowserFrame(this, browser_view_); - views::Widget::InitParams params = native_browser_frame_->GetWidgetParams(); + views::Widget::InitParams params; params.delegate = browser_view_; + params.native_widget = native_browser_frame_->AsNativeWidget(); if (browser_view_->browser()->is_type_tabbed()) { // Typed panel/popup can only return a size once the widget has been // created. @@ -82,9 +100,46 @@ void BrowserFrame::InitBrowserFrame() { ¶ms.bounds, ¶ms.show_state); } + + if (browser_view_->browser()->host_desktop_type() == + chrome::HOST_DESKTOP_TYPE_ASH || chrome::ShouldOpenAshOnStartup()) { + params.context = ash::Shell::GetPrimaryRootWindow(); +#if defined(OS_WIN) + // If this window is under ASH on Windows, we need it to be translucent. + params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; +#endif + } + +#if defined(OS_LINUX) && !defined(OS_CHROMEOS) + // Set up a custom WM_CLASS for some sorts of window types. This allows + // task switchers in X11 environments to distinguish between main browser + // windows and e.g app windows. + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + const Browser& browser = *browser_view_->browser(); + params.wm_class_class = shell_integration_linux::GetProgramClassName(); + params.wm_class_name = params.wm_class_class; + if (browser.is_app() && !browser.is_devtools()) { + // This window is a hosted app or v1 packaged app. + // NOTE: v2 packaged app windows are created by ChromeNativeAppWindowViews. + params.wm_class_name = web_app::GetWMClassFromAppName(browser.app_name()); + } else if (command_line.HasSwitch(switches::kUserDataDir)) { + // Set the class name to e.g. "Chrome (/tmp/my-user-data)". The + // class name will show up in the alt-tab list in gnome-shell if + // you're running a binary that doesn't have a matching .desktop + // file. + const std::string user_data_dir = + command_line.GetSwitchValueNative(switches::kUserDataDir); + params.wm_class_name += " (" + user_data_dir + ")"; + } + const char kX11WindowRoleBrowser[] = "browser"; + const char kX11WindowRolePopup[] = "pop-up"; + params.wm_role_name = browser_view_->browser()->is_type_tabbed() ? + std::string(kX11WindowRoleBrowser) : std::string(kX11WindowRolePopup); + params.remove_standard_frame = UseCustomFrame(); set_frame_type(UseCustomFrame() ? Widget::FRAME_TYPE_FORCE_CUSTOM : Widget::FRAME_TYPE_FORCE_NATIVE); +#endif // defined(OS_LINUX) Init(params); @@ -93,9 +148,8 @@ void BrowserFrame::InitBrowserFrame() { non_client_view()->set_context_menu_controller(this); } -#if defined(USE_X11) - browser_command_handler_.reset(new BrowserCommandHandlerX11(browser_view_)); -#endif + if (browser_command_handler_) + GetNativeWindow()->AddPreTargetHandler(browser_command_handler_.get()); } void BrowserFrame::SetThemeProvider(scoped_ptr provider) { diff --git a/chrome/browser/ui/views/frame/browser_frame_ash.cc b/chrome/browser/ui/views/frame/browser_frame_ash.cc index 563f309d1c8f6..9f576dc749cf9 100644 --- a/chrome/browser/ui/views/frame/browser_frame_ash.cc +++ b/chrome/browser/ui/views/frame/browser_frame_ash.cc @@ -4,7 +4,6 @@ #include "chrome/browser/ui/views/frame/browser_frame_ash.h" -#include "ash/shell.h" #include "ash/wm/window_properties.h" #include "ash/wm/window_state.h" #include "ash/wm/window_state_delegate.h" @@ -18,6 +17,8 @@ #include "ui/aura/window_observer.h" #include "ui/views/view.h" +using aura::Window; + namespace { // BrowserWindowStateDelegate class handles a user's fullscreen @@ -126,17 +127,12 @@ void BrowserFrameAsh::GetWindowPlacement( //////////////////////////////////////////////////////////////////////////////// // BrowserFrameAsh, NativeBrowserFrame implementation: -views::Widget::InitParams BrowserFrameAsh::GetWidgetParams() { - views::Widget::InitParams params; - params.native_widget = this; - - params.context = ash::Shell::GetPrimaryRootWindow(); -#if defined(OS_WIN) - // If this window is under ASH on Windows, we need it to be translucent. - params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; -#endif +views::NativeWidget* BrowserFrameAsh::AsNativeWidget() { + return this; +} - return params; +const views::NativeWidget* BrowserFrameAsh::AsNativeWidget() const { + return this; } bool BrowserFrameAsh::UsesNativeSystemMenu() const { diff --git a/chrome/browser/ui/views/frame/browser_frame_ash.h b/chrome/browser/ui/views/frame/browser_frame_ash.h index 55c82bea54dd4..bd827c6e264b0 100644 --- a/chrome/browser/ui/views/frame/browser_frame_ash.h +++ b/chrome/browser/ui/views/frame/browser_frame_ash.h @@ -34,7 +34,8 @@ class BrowserFrameAsh : public views::NativeWidgetAura, void OnWindowTargetVisibilityChanged(bool visible) override; // Overridden from NativeBrowserFrame: - views::Widget::InitParams GetWidgetParams() override; + views::NativeWidget* AsNativeWidget() override; + const views::NativeWidget* AsNativeWidget() const override; bool UsesNativeSystemMenu() const override; int GetMinimizeButtonOffset() const override; bool ShouldSaveWindowPlacement() const override; diff --git a/chrome/browser/ui/views/frame/browser_frame_mac.h b/chrome/browser/ui/views/frame/browser_frame_mac.h deleted file mode 100644 index 86f74459c53ed..0000000000000 --- a/chrome/browser/ui/views/frame/browser_frame_mac.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_FRAME_MAC_H_ -#define CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_FRAME_MAC_H_ - -#include "chrome/browser/ui/views/frame/native_browser_frame.h" -#include "ui/views/widget/native_widget_mac.h" - -class BrowserFrame; -class BrowserView; - -//////////////////////////////////////////////////////////////////////////////// -// BrowserFrameMac is a NativeWidgetMac subclass that provides -// the window frame for the Chrome browser window. -// -class BrowserFrameMac : public views::NativeWidgetMac, - public NativeBrowserFrame { - public: - BrowserFrameMac(BrowserFrame* browser_frame, BrowserView* browser_view); - - // Overridden from NativeBrowserFrame: - views::Widget::InitParams GetWidgetParams() override; - bool UsesNativeSystemMenu() const override; - bool ShouldSaveWindowPlacement() const override; - void GetWindowPlacement(gfx::Rect* bounds, - ui::WindowShowState* show_state) const override; - - protected: - ~BrowserFrameMac() override; - - // Overridden from NativeBrowserFrame: - int GetMinimizeButtonOffset() const override; - - private: - DISALLOW_COPY_AND_ASSIGN(BrowserFrameMac); -}; - -#endif // CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_FRAME_MAC_H_ diff --git a/chrome/browser/ui/views/frame/browser_frame_mac.mm b/chrome/browser/ui/views/frame/browser_frame_mac.mm deleted file mode 100644 index ee6c55c622e8a..0000000000000 --- a/chrome/browser/ui/views/frame/browser_frame_mac.mm +++ /dev/null @@ -1,43 +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 "chrome/browser/ui/views/frame/browser_frame_mac.h" - -#include "chrome/browser/ui/views/frame/browser_frame.h" - -BrowserFrameMac::BrowserFrameMac(BrowserFrame* browser_frame, - BrowserView* browser_view) - : views::NativeWidgetMac(browser_frame) { -} - -BrowserFrameMac::~BrowserFrameMac() { -} - -//////////////////////////////////////////////////////////////////////////////// -// BrowserFrameMac, NativeBrowserFrame implementation: - -views::Widget::InitParams BrowserFrameMac::GetWidgetParams() { - views::Widget::InitParams params; - params.native_widget = this; - return params; -} - -bool BrowserFrameMac::UsesNativeSystemMenu() const { - return true; -} - -bool BrowserFrameMac::ShouldSaveWindowPlacement() const { - return true; -} - -void BrowserFrameMac::GetWindowPlacement( - gfx::Rect* bounds, - ui::WindowShowState* show_state) const { - return NativeWidgetMac::GetWindowPlacement(bounds, show_state); -} - -int BrowserFrameMac::GetMinimizeButtonOffset() const { - NOTIMPLEMENTED(); - return 0; -} diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc index a49c3873a10f8..a6a3872d05848 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc @@ -119,9 +119,16 @@ void BrowserNonClientFrameView::UpdateAvatarInfo() { gfx::Image avatar; gfx::Image taskbar_badge_avatar; bool is_rectangle = false; - AvatarMenuButton::GetAvatarImages(browser_view_->browser()->profile(), - &avatar, &taskbar_badge_avatar, - &is_rectangle); + + // Update the avatar button in the window frame and the taskbar overlay. + bool should_show_avatar_menu = + avatar_button_ || AvatarMenu::ShouldShowAvatarMenu(); + + if (!AvatarMenuButton::GetAvatarImages( + browser_view_->browser()->profile(), should_show_avatar_menu, &avatar, + &taskbar_badge_avatar, &is_rectangle)) { + return; + } // Disable the menu when we should not show the menu. if (avatar_button_ && !AvatarMenu::ShouldShowAvatarMenu()) @@ -194,8 +201,9 @@ void BrowserNonClientFrameView::OnProfileAvatarChanged( gfx::Image avatar; gfx::Image taskbar_badge_avatar; bool is_rectangle; + // Only need to update the taskbar overlay here. AvatarMenuButton::GetAvatarImages(browser_view_->browser()->profile(), - &avatar, &taskbar_badge_avatar, - &is_rectangle); + AvatarMenu::ShouldShowAvatarMenu(), &avatar, + &taskbar_badge_avatar, &is_rectangle); DrawTaskbarDecoration(avatar, taskbar_badge_avatar); } diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index 07205733fa931..150d2020060da 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc @@ -68,12 +68,14 @@ #include "chrome/browser/ui/views/frame/browser_view_layout_delegate.h" #include "chrome/browser/ui/views/frame/contents_layout_manager.h" #include "chrome/browser/ui/views/frame/immersive_mode_controller.h" +#include "chrome/browser/ui/views/frame/native_browser_frame_factory.h" #include "chrome/browser/ui/views/frame/top_container_view.h" #include "chrome/browser/ui/views/frame/web_contents_close_handler.h" #include "chrome/browser/ui/views/fullscreen_exit_bubble_views.h" #include "chrome/browser/ui/views/infobars/infobar_container_view.h" #include "chrome/browser/ui/views/location_bar/location_bar_view.h" #include "chrome/browser/ui/views/location_bar/location_icon_view.h" +#include "chrome/browser/ui/views/location_bar/zoom_bubble_view.h" #include "chrome/browser/ui/views/omnibox/omnibox_view_views.h" #include "chrome/browser/ui/views/profiles/avatar_menu_bubble_view.h" #include "chrome/browser/ui/views/profiles/avatar_menu_button.h" @@ -107,12 +109,14 @@ #include "content/public/browser/notification_service.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_view_host.h" -#include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/user_metrics.h" #include "content/public/browser/web_contents.h" #include "content/public/common/content_switches.h" #include "grit/theme_resources.h" #include "ui/accessibility/ax_view_state.h" +#include "ui/aura/client/window_tree_client.h" +#include "ui/aura/window.h" +#include "ui/aura/window_tree_host.h" #include "ui/base/accelerators/accelerator.h" #include "ui/base/hit_test.h" #include "ui/base/l10n/l10n_util.h" @@ -135,12 +139,6 @@ #include "ui/views/widget/widget.h" #include "ui/views/window/dialog_delegate.h" -#if defined(USE_AURA) -#include "ui/aura/client/window_tree_client.h" -#include "ui/aura/window.h" -#include "ui/aura/window_tree_host.h" -#endif - #if defined(OS_WIN) #include "base/win/windows_version.h" #include "chrome/browser/jumplist_win.h" @@ -824,6 +822,9 @@ void BrowserView::OnActiveTabChanged(content::WebContents* old_contents, // Update all the UI bits. UpdateTitleBar(); + + TranslateBubbleView::CloseBubble(); + ZoomBubbleView::CloseBubble(); } void BrowserView::ZoomChangedForActiveTab(bool can_show_bubble) { @@ -1419,7 +1420,6 @@ ToolbarView* BrowserView::GetToolbarView() const { void BrowserView::TabInsertedAt(WebContents* contents, int index, bool foreground) { -#if defined(USE_AURA) // WebContents inserted in tabs might not have been added to the root // window yet. Per http://crbug/342672 add them now since drawing the // WebContents requires root window specific data - information about @@ -1431,7 +1431,6 @@ void BrowserView::TabInsertedAt(WebContents* contents, window, root_window, root_window->GetBoundsInScreen()); DCHECK(contents->GetNativeView()->GetRootWindow()); } -#endif web_contents_close_handler_->TabInserted(); if (foreground) @@ -2371,6 +2370,24 @@ void BrowserView::UpdateAcceleratorMetrics(const ui::Accelerator& accelerator, #endif } +// static +BrowserWindow* BrowserWindow::CreateBrowserWindow(Browser* browser) { + // Create the view and the frame. The frame will attach itself via the view + // so we don't need to do anything with the pointer. + BrowserView* view = new BrowserView(); + view->Init(browser); + (new BrowserFrame(view))->InitBrowserFrame(); + view->GetWidget()->non_client_view()->SetAccessibleName( + l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)); + return view; +} + +// static +chrome::HostDesktopType BrowserWindow::AdjustHostDesktopType( + chrome::HostDesktopType desktop_type) { + return NativeBrowserFrameFactory::AdjustHostDesktopType(desktop_type); +} + void BrowserView::ShowAvatarBubble(WebContents* web_contents, const gfx::Rect& rect) { gfx::Point origin(rect.origin()); @@ -2464,7 +2481,10 @@ void BrowserView::DoCutCopyPaste(void (WebContents::*method)(), bool BrowserView::DoCutCopyPasteForWebContents( WebContents* contents, void (WebContents::*method)()) { - if (contents->GetRenderWidgetHostView()->HasFocus()) { + gfx::NativeView native_view = contents->GetContentNativeView(); + if (!native_view) + return false; + if (native_view->HasFocus()) { (contents->*method)(); return true; } diff --git a/chrome/browser/ui/views/frame/browser_window_factory.cc b/chrome/browser/ui/views/frame/browser_window_factory.cc deleted file mode 100644 index 7db63a843348f..0000000000000 --- a/chrome/browser/ui/views/frame/browser_window_factory.cc +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/views/frame/browser_frame.h" -#include "chrome/browser/ui/views/frame/browser_view.h" -#include "chrome/browser/ui/views/frame/native_browser_frame_factory.h" -#include "chrome/grit/chromium_strings.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/views/widget/widget.h" - -// static -BrowserWindow* BrowserWindow::CreateBrowserWindow(Browser* browser) { - // Create the view and the frame. The frame will attach itself via the view - // so we don't need to do anything with the pointer. - BrowserView* view = new BrowserView(); - view->Init(browser); - (new BrowserFrame(view))->InitBrowserFrame(); - view->GetWidget()->non_client_view()->SetAccessibleName( - l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)); - return view; -} - -// static -chrome::HostDesktopType BrowserWindow::AdjustHostDesktopType( - chrome::HostDesktopType desktop_type) { - return NativeBrowserFrameFactory::AdjustHostDesktopType(desktop_type); -} diff --git a/chrome/browser/ui/views/frame/contents_web_view.cc b/chrome/browser/ui/views/frame/contents_web_view.cc index 68f0243ca2e45..a86e39c4ebfbf 100644 --- a/chrome/browser/ui/views/frame/contents_web_view.cc +++ b/chrome/browser/ui/views/frame/contents_web_view.cc @@ -7,14 +7,11 @@ #include "chrome/browser/themes/theme_properties.h" #include "chrome/browser/ui/views/status_bubble_views.h" #include "content/public/browser/web_contents.h" +#include "ui/aura/window.h" #include "ui/base/theme_provider.h" #include "ui/compositor/layer_tree_owner.h" #include "ui/views/background.h" - -#if defined(USE_AURA) -#include "ui/aura/window.h" #include "ui/wm/core/window_util.h" -#endif ContentsWebView::ContentsWebView(content::BrowserContext* browser_context) : views::WebView(browser_context), @@ -86,11 +83,7 @@ void ContentsWebView::OnLayerRecreated(ui::Layer* old_layer, void ContentsWebView::CloneWebContentsLayer() { if (!web_contents()) return; -#if defined(USE_AURA) - // We don't need to clone the layers on non-Aura (Mac), because closing an - // NSWindow does not animate. cloned_layer_tree_ = wm::RecreateLayers(web_contents()->GetNativeView()); -#endif if (!cloned_layer_tree_ || !cloned_layer_tree_->root()) { cloned_layer_tree_.reset(); return; diff --git a/chrome/browser/ui/views/frame/desktop_browser_frame_aura.cc b/chrome/browser/ui/views/frame/desktop_browser_frame_aura.cc index 6063c767dcc95..d251f4f0305c2 100644 --- a/chrome/browser/ui/views/frame/desktop_browser_frame_aura.cc +++ b/chrome/browser/ui/views/frame/desktop_browser_frame_aura.cc @@ -4,13 +4,10 @@ #include "chrome/browser/ui/views/frame/desktop_browser_frame_aura.h" -#include "base/command_line.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/ui/views/frame/browser_desktop_window_tree_host.h" #include "chrome/browser/ui/views/frame/browser_shutdown.h" #include "chrome/browser/ui/views/frame/browser_view.h" -#include "chrome/browser/web_applications/web_app.h" -#include "chrome/common/chrome_switches.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h" @@ -21,10 +18,6 @@ #include "ui/views/view.h" #include "ui/wm/core/visibility_controller.h" -#if defined(OS_LINUX) -#include "chrome/browser/shell_integration_linux.h" -#endif - using aura::Window; /////////////////////////////////////////////////////////////////////////////// @@ -81,39 +74,12 @@ void DesktopBrowserFrameAura::InitNativeWidget( //////////////////////////////////////////////////////////////////////////////// // DesktopBrowserFrameAura, NativeBrowserFrame implementation: -views::Widget::InitParams DesktopBrowserFrameAura::GetWidgetParams() { - views::Widget::InitParams params; - params.native_widget = this; - -#if defined(OS_LINUX) - // Set up a custom WM_CLASS for some sorts of window types. This allows - // task switchers in X11 environments to distinguish between main browser - // windows and e.g app windows. - const base::CommandLine& command_line = - *base::CommandLine::ForCurrentProcess(); - const Browser& browser = *browser_view_->browser(); - params.wm_class_class = shell_integration_linux::GetProgramClassName(); - params.wm_class_name = params.wm_class_class; - if (browser.is_app() && !browser.is_devtools()) { - // This window is a hosted app or v1 packaged app. - // NOTE: v2 packaged app windows are created by ChromeNativeAppWindowViews. - params.wm_class_name = web_app::GetWMClassFromAppName(browser.app_name()); - } else if (command_line.HasSwitch(switches::kUserDataDir)) { - // Set the class name to e.g. "Chrome (/tmp/my-user-data)". The - // class name will show up in the alt-tab list in gnome-shell if - // you're running a binary that doesn't have a matching .desktop - // file. - const std::string user_data_dir = - command_line.GetSwitchValueNative(switches::kUserDataDir); - params.wm_class_name += " (" + user_data_dir + ")"; - } - const char kX11WindowRoleBrowser[] = "browser"; - const char kX11WindowRolePopup[] = "pop-up"; - params.wm_role_name = browser_view_->browser()->is_type_tabbed() ? - std::string(kX11WindowRoleBrowser) : std::string(kX11WindowRolePopup); -#endif // defined(OS_LINUX) - - return params; +views::NativeWidget* DesktopBrowserFrameAura::AsNativeWidget() { + return this; +} + +const views::NativeWidget* DesktopBrowserFrameAura::AsNativeWidget() const { + return this; } bool DesktopBrowserFrameAura::UsesNativeSystemMenu() const { diff --git a/chrome/browser/ui/views/frame/desktop_browser_frame_aura.h b/chrome/browser/ui/views/frame/desktop_browser_frame_aura.h index cd86478a262b6..901fa3e87dbb7 100644 --- a/chrome/browser/ui/views/frame/desktop_browser_frame_aura.h +++ b/chrome/browser/ui/views/frame/desktop_browser_frame_aura.h @@ -41,7 +41,8 @@ class DesktopBrowserFrameAura : public views::DesktopNativeWidgetAura, void InitNativeWidget(const views::Widget::InitParams& params) override; // Overridden from NativeBrowserFrame: - views::Widget::InitParams GetWidgetParams() override; + views::NativeWidget* AsNativeWidget() override; + const views::NativeWidget* AsNativeWidget() const override; bool UsesNativeSystemMenu() const override; int GetMinimizeButtonOffset() const override; bool ShouldSaveWindowPlacement() const override; diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller.h b/chrome/browser/ui/views/frame/immersive_mode_controller.h index 2e059f34ddece..6f24dddf14fd7 100644 --- a/chrome/browser/ui/views/frame/immersive_mode_controller.h +++ b/chrome/browser/ui/views/frame/immersive_mode_controller.h @@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_UI_VIEWS_FRAME_IMMERSIVE_MODE_CONTROLLER_H_ #define CHROME_BROWSER_UI_VIEWS_FRAME_IMMERSIVE_MODE_CONTROLLER_H_ +#include "ash/wm/immersive_revealed_lock.h" #include "base/compiler_specific.h" #include "base/observer_list.h" #include "chrome/browser/ui/host_desktop.h" @@ -16,16 +17,7 @@ class Rect; class Size; } -// A lock which will keep the top-of-window views revealed for its -// lifetime. -// See ImmersiveModeController::GetRevealedLock for details. -class ImmersiveRevealedLock { - public: - virtual ~ImmersiveRevealedLock() {} - - protected: - ImmersiveRevealedLock() {} -}; +typedef ash::ImmersiveRevealedLock ImmersiveRevealedLock; // Controller for an "immersive mode" similar to MacOS presentation mode where // the top-of-window views are hidden until the mouse hits the top of the @@ -90,7 +82,6 @@ class ImmersiveModeController { // If acquiring the lock causes a reveal, the top-of-window views will animate // according to |animate_reveal|. // The caller takes ownership of the returned lock. - // This is currently only supported on Ash. virtual ImmersiveRevealedLock* GetRevealedLock( AnimateReveal animate_reveal) WARN_UNUSED_RESULT = 0; diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc index 17928ea04ea54..d7f12d2ab7e67 100644 --- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc +++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc @@ -5,7 +5,6 @@ #include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h" #include "ash/shell.h" -#include "ash/wm/immersive_revealed_lock.h" #include "ash/wm/window_state.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/ui/fullscreen/fullscreen_controller.h" @@ -41,17 +40,6 @@ ToImmersiveFullscreenControllerAnimateReveal( return ash::ImmersiveFullscreenController::ANIMATE_REVEAL_NO; } -class ImmersiveRevealedLockAsh : public ImmersiveRevealedLock { - public: - explicit ImmersiveRevealedLockAsh(ash::ImmersiveRevealedLock* lock) - : lock_(lock) {} - - private: - scoped_ptr lock_; - - DISALLOW_COPY_AND_ASSIGN(ImmersiveRevealedLockAsh); -}; - } // namespace ImmersiveModeControllerAsh::ImmersiveModeControllerAsh() @@ -120,8 +108,8 @@ int ImmersiveModeControllerAsh::GetTopContainerVerticalOffset( ImmersiveRevealedLock* ImmersiveModeControllerAsh::GetRevealedLock( AnimateReveal animate_reveal) { - return new ImmersiveRevealedLockAsh(controller_->GetRevealedLock( - ToImmersiveFullscreenControllerAnimateReveal(animate_reveal))); + return controller_->GetRevealedLock( + ToImmersiveFullscreenControllerAnimateReveal(animate_reveal)); } void ImmersiveModeControllerAsh::OnFindBarVisibleBoundsChanged( diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_factory_ash.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_factory.cc similarity index 100% rename from chrome/browser/ui/views/frame/immersive_mode_controller_factory_ash.cc rename to chrome/browser/ui/views/frame/immersive_mode_controller_factory.cc index 1d8848ae58ddd..7edd1401fa795 100644 --- a/chrome/browser/ui/views/frame/immersive_mode_controller_factory_ash.cc +++ b/chrome/browser/ui/views/frame/immersive_mode_controller_factory.cc @@ -3,8 +3,8 @@ // found in the LICENSE file. #include "chrome/browser/ui/host_desktop.h" -#include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h" #include "chrome/browser/ui/views/frame/immersive_mode_controller_stub.h" +#include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h" namespace chrome { diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_factory_mac.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_factory_mac.cc deleted file mode 100644 index 9a0849ffffe3f..0000000000000 --- a/chrome/browser/ui/views/frame/immersive_mode_controller_factory_mac.cc +++ /dev/null @@ -1,14 +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 "chrome/browser/ui/views/frame/immersive_mode_controller_stub.h" - -namespace chrome { - -ImmersiveModeController* CreateImmersiveModeController( - chrome::HostDesktopType host_desktop_type) { - return new ImmersiveModeControllerStub(); -} - -} // namespace chrome diff --git a/chrome/browser/ui/views/frame/native_browser_frame.h b/chrome/browser/ui/views/frame/native_browser_frame.h index f1d2f38427ffd..846d9e7f9b4b9 100644 --- a/chrome/browser/ui/views/frame/native_browser_frame.h +++ b/chrome/browser/ui/views/frame/native_browser_frame.h @@ -7,7 +7,6 @@ #include "ui/base/ui_base_types.h" #include "ui/gfx/rect.h" -#include "ui/views/widget/widget.h" class BrowserFrame; class BrowserView; @@ -20,8 +19,8 @@ class NativeBrowserFrame { public: virtual ~NativeBrowserFrame() {} - // Returns the platform specific InitParams for initializing our widget. - virtual views::Widget::InitParams GetWidgetParams() = 0; + virtual views::NativeWidget* AsNativeWidget() = 0; + virtual const views::NativeWidget* AsNativeWidget() const = 0; // Returns true if the OS takes care of showing the system menu. Returning // false means BrowserFrame handles showing the system menu. diff --git a/chrome/browser/ui/views/frame/native_browser_frame_factory_mac.cc b/chrome/browser/ui/views/frame/native_browser_frame_factory_mac.cc deleted file mode 100644 index 27ca19213d3ea..0000000000000 --- a/chrome/browser/ui/views/frame/native_browser_frame_factory_mac.cc +++ /dev/null @@ -1,13 +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 "chrome/browser/ui/views/frame/native_browser_frame_factory.h" - -#include "chrome/browser/ui/views/frame/browser_frame_mac.h" - -NativeBrowserFrame* NativeBrowserFrameFactory::Create( - BrowserFrame* browser_frame, - BrowserView* browser_view) { - return new BrowserFrameMac(browser_frame, browser_view); -} diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc index f842e321f8c59..4cd95986ed965 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.cc +++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc @@ -971,8 +971,6 @@ void LocationBarView::Update(const WebContents* contents) { browser_->search_model()->voice_search_supported()); RefreshContentSettingViews(); generated_credit_card_view_->Update(); - ZoomBubbleView::CloseBubble(); - TranslateBubbleView::CloseBubble(); RefreshZoomView(); RefreshPageActionViews(); RefreshTranslateIcon(); @@ -1138,6 +1136,8 @@ bool LocationBarView::RefreshZoomView() { return false; const bool was_visible = zoom_view_->visible(); zoom_view_->Update(ZoomController::FromWebContents(web_contents)); + if (!zoom_view_->visible()) + ZoomBubbleView::CloseBubble(); return was_visible != zoom_view_->visible(); } @@ -1154,6 +1154,8 @@ void LocationBarView::RefreshTranslateIcon() { command_updater()->UpdateCommandEnabled(IDC_TRANSLATE_PAGE, enabled); translate_icon_view_->SetVisible(enabled); translate_icon_view_->SetToggled(language_state.IsPageTranslated()); + if (!enabled) + TranslateBubbleView::CloseBubble(); } bool LocationBarView::RefreshManagePasswordsIconView() { diff --git a/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc b/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc index 081b8b2e8256a..fd6b6ae60c361 100644 --- a/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc +++ b/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc @@ -69,6 +69,7 @@ void ZoomBubbleView::ShowBubble(content::WebContents* web_contents, if (zoom_bubble_ && zoom_bubble_->GetAnchorView() == anchor_view && !extension) { + DCHECK_EQ(web_contents, zoom_bubble_->web_contents_); zoom_bubble_->Refresh(); return; } @@ -174,6 +175,10 @@ void ZoomBubbleView::Refresh() { } void ZoomBubbleView::Close() { + // Widget's Close() is async, but we don't want to use zoom_bubble_ after + // this. Additionally web_contents_ may have been destroyed. + zoom_bubble_ = NULL; + web_contents_ = NULL; GetWidget()->Close(); } diff --git a/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc b/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc index a8068ba79351d..e76c8cc737ee3 100644 --- a/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc +++ b/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc @@ -95,7 +95,7 @@ IN_PROC_BROWSER_TEST_F(ZoomBubbleBrowserTest, ImmersiveFullscreen) { immersive_controller->GetRevealedLock( ImmersiveModeController::ANIMATE_REVEAL_NO)); ASSERT_TRUE(immersive_controller->IsRevealed()); - EXPECT_TRUE(ZoomBubbleView::zoom_bubble_->GetWidget()->IsClosed()); + EXPECT_EQ(NULL, ZoomBubbleView::zoom_bubble_); // The zoom bubble should be anchored when it is shown in immersive fullscreen // and the top-of-window views are revealed. diff --git a/chrome/browser/ui/views/profiles/avatar_menu_button.cc b/chrome/browser/ui/views/profiles/avatar_menu_button.cc index 65d8452a84464..a63e79c8543ea 100644 --- a/chrome/browser/ui/views/profiles/avatar_menu_button.cc +++ b/chrome/browser/ui/views/profiles/avatar_menu_button.cc @@ -95,10 +95,11 @@ void AvatarMenuButton::SetAvatarIcon(const gfx::Image& icon, } // static -void AvatarMenuButton::GetAvatarImages(Profile* profile, +bool AvatarMenuButton::GetAvatarImages(Profile* profile, + bool should_show_avatar_menu, gfx::Image* avatar, gfx::Image* taskbar_badge_avatar, - bool *is_rectangle) { + bool* is_rectangle) { ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); if (profile->GetProfileType() == Profile::GUEST_PROFILE) { *avatar = rb. @@ -114,12 +115,12 @@ void AvatarMenuButton::GetAvatarImages(Profile* profile, taskbar_badge_avatar, &is_badge_rectangle); #endif - } else if (AvatarMenu::ShouldShowAvatarMenu()) { + } else if (should_show_avatar_menu) { ProfileInfoCache& cache = g_browser_process->profile_manager()->GetProfileInfoCache(); size_t index = cache.GetIndexOfProfileWithPath(profile->GetPath()); if (index == std::string::npos) - return; + return false; if (switches::IsNewAvatarMenu()) { *avatar = cache.GetAvatarIconOfProfileAtIndex(index); @@ -138,6 +139,7 @@ void AvatarMenuButton::GetAvatarImages(Profile* profile, AvatarMenu::GetImageForMenuButton(profile, avatar, is_rectangle); } } + return true; } // views::ViewTargeterDelegate: diff --git a/chrome/browser/ui/views/profiles/avatar_menu_button.h b/chrome/browser/ui/views/profiles/avatar_menu_button.h index 6bab639641d8f..343e4670fda97 100644 --- a/chrome/browser/ui/views/profiles/avatar_menu_button.h +++ b/chrome/browser/ui/views/profiles/avatar_menu_button.h @@ -54,11 +54,13 @@ class AvatarMenuButton : public views::MenuButton, // Get avatar images for the profile. |avatar| is used in the browser window // whereas |taskbar_badge_avatar| is used for the OS taskbar. If // |taskbar_badge_avatar| is empty then |avatar| should be used for the - // taskbar as well. - static void GetAvatarImages(Profile* profile, + // taskbar as well. Returns false if the cache doesn't have an entry for a + // Profile::REGULAR_PROFILE type |profile|, otherwise return true. + static bool GetAvatarImages(Profile* profile, + bool should_show_avatar_menu, gfx::Image* avatar, gfx::Image* taskbar_badge_avatar, - bool *is_rectangle); + bool* is_rectangle); private: // views::ViewTargeterDelegate: diff --git a/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc b/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc index 7c1ede9673e43..40c51672a98fd 100644 --- a/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc +++ b/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc @@ -138,8 +138,7 @@ class SelectFileDialogExtensionBrowserTest : public ExtensionBrowserTest { const std::string& additional_message) { // Spawn a dialog to open a file. The dialog will signal that it is ready // via chrome.test.sendMessage() in the extension JavaScript. - ExtensionTestMessageListener init_listener("worker-initialized", - false /* will_reply */); + ExtensionTestMessageListener init_listener("ready", false /* will_reply */); scoped_ptr additional_listener; if (!additional_message.empty()) { @@ -278,8 +277,6 @@ IN_PROC_BROWSER_TEST_F(SelectFileDialogExtensionBrowserTest, // Spawn a dialog to open a file. Provide the path to the file so the dialog // will automatically select it. Ensure that the OK button is enabled by // waiting for chrome.test.sendMessage('selection-change-complete'). - // The extension starts a Web Worker to read file metadata, so it may send - // 'selection-change-complete' before 'worker-initialized'. This is OK. ASSERT_NO_FATAL_FAILURE(OpenDialog(ui::SelectFileDialog::SELECT_OPEN_FILE, test_file, owning_window, "selection-change-complete")); @@ -306,8 +303,6 @@ IN_PROC_BROWSER_TEST_F(SelectFileDialogExtensionBrowserTest, // Spawn a dialog to save a file, providing a suggested path. // Ensure "Save" button is enabled by waiting for notification from // chrome.test.sendMessage(). - // The extension starts a Web Worker to read file metadata, so it may send - // 'directory-change-complete' before 'worker-initialized'. This is OK. ASSERT_NO_FATAL_FAILURE(OpenDialog(ui::SelectFileDialog::SELECT_SAVEAS_FILE, test_file, owning_window, "directory-change-complete")); diff --git a/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.cc b/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.cc index b882cc520c2d7..50dc01f94deda 100644 --- a/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.cc +++ b/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.cc @@ -153,9 +153,6 @@ void ChromeWebContentsViewDelegateViews::ShowDisambiguationPopup( const base::Callback& gesture_cb, const base::Callback& mouse_cb) { #if defined(USE_AURA) - if (!browser_defaults::kShowLinkDisambiguationPopup) - return; - link_disambiguation_popup_.reset(new LinkDisambiguationPopup); link_disambiguation_popup_->Show( views::Widget::GetTopLevelWidgetForNativeView(GetActiveNativeView()), diff --git a/chrome/browser/ui/views/toolbar/chevron_menu_button.cc b/chrome/browser/ui/views/toolbar/chevron_menu_button.cc index a965b47d64484..68f9340bdc4cd 100644 --- a/chrome/browser/ui/views/toolbar/chevron_menu_button.cc +++ b/chrome/browser/ui/views/toolbar/chevron_menu_button.cc @@ -416,16 +416,24 @@ void ChevronMenuButton::OnDragExited() { } int ChevronMenuButton::OnPerformDrop(const ui::DropTargetEvent& event) { + weak_factory_.InvalidateWeakPtrs(); return ui::DragDropTypes::DRAG_MOVE; } void ChevronMenuButton::OnMenuButtonClicked(views::View* source, const gfx::Point& point) { DCHECK_EQ(this, source); - ShowOverflowMenu(false); + // The menu could already be open if a user dragged an item over it but + // ultimately dropped elsewhere (as in that case the menu will close on a + // timer). In this case, the click should close the open menu. + if (menu_controller_) + menu_controller_->CloseMenu(); + else + ShowOverflowMenu(false); } void ChevronMenuButton::ShowOverflowMenu(bool for_drop) { + // We should never try to show an overflow menu when one is already visible. DCHECK(!menu_controller_); menu_controller_.reset(new MenuController( this, browser_actions_container_, for_drop)); diff --git a/chrome/browser/ui/website_settings/website_settings.cc b/chrome/browser/ui/website_settings/website_settings.cc index ac71f0eb51dd2..ac3548853b79a 100644 --- a/chrome/browser/ui/website_settings/website_settings.cc +++ b/chrome/browser/ui/website_settings/website_settings.cc @@ -81,6 +81,9 @@ ContentSettingsType kPermissionType[] = { CONTENT_SETTINGS_TYPE_MEDIASTREAM, CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, CONTENT_SETTINGS_TYPE_MIDI_SYSEX, +#if defined(OS_ANDROID) + CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, +#endif }; bool CertificateTransparencyStatusMatch( @@ -256,6 +259,7 @@ void WebsiteSettings::OnSitePermissionChanged(ContentSettingsType type, case CONTENT_SETTINGS_TYPE_FULLSCREEN: case CONTENT_SETTINGS_TYPE_MOUSELOCK: case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS: + case CONTENT_SETTINGS_TYPE_PUSH_MESSAGING: primary_pattern = ContentSettingsPattern::FromURL(site_url_); secondary_pattern = ContentSettingsPattern::Wildcard(); break; diff --git a/chrome/browser/ui/website_settings/website_settings_ui.cc b/chrome/browser/ui/website_settings/website_settings_ui.cc index 4232aa7835f3c..21d7f6494a3e7 100644 --- a/chrome/browser/ui/website_settings/website_settings_ui.cc +++ b/chrome/browser/ui/website_settings/website_settings_ui.cc @@ -119,6 +119,7 @@ base::string16 WebsiteSettingsUI::PermissionTypeToUIString( case CONTENT_SETTINGS_TYPE_GEOLOCATION: return l10n_util::GetStringUTF16(IDS_WEBSITE_SETTINGS_TYPE_LOCATION); case CONTENT_SETTINGS_TYPE_NOTIFICATIONS: + case CONTENT_SETTINGS_TYPE_PUSH_MESSAGING: return l10n_util::GetStringUTF16( IDS_WEBSITE_SETTINGS_TYPE_NOTIFICATIONS); case CONTENT_SETTINGS_TYPE_FULLSCREEN: diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc index 94fd12d720d8d..3e5210cad7aa6 100644 --- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc @@ -20,6 +20,7 @@ #include "chrome/browser/chromeos/login/error_screens_histogram_helper.h" #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h" #include "chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.h" +#include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/extensions/signin/gaia_auth_extension_loader.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" @@ -117,6 +118,7 @@ EnrollmentScreenHandler::EnrollmentScreenHandler( network_state_informer_(network_state_informer), error_screen_actor_(error_screen_actor), histogram_helper_(new ErrorScreensHistogramHelper("Enrollment")), + auth_extension_(nullptr), weak_ptr_factory_(this) { set_async_assets_load_id(OobeUI::kScreenOobeEnrollment); DCHECK(network_state_informer_.get()); @@ -173,6 +175,11 @@ void EnrollmentScreenHandler::PrepareToShow() { } void EnrollmentScreenHandler::Show() { + if (!auth_extension_) { + Profile* signin_profile = ProfileHelper::GetSigninProfile(); + auth_extension_.reset(new ScopedGaiaAuthExtension(signin_profile)); + } + if (!page_is_ready()) show_on_init_ = true; else diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h index 004ddb1e38086..6c5946fccbadf 100644 --- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h @@ -15,6 +15,7 @@ #include "chrome/browser/browsing_data/browsing_data_remover.h" #include "chrome/browser/chromeos/login/enrollment/enrollment_screen_actor.h" #include "chrome/browser/chromeos/login/ui/webui_login_view.h" +#include "chrome/browser/extensions/signin/scoped_gaia_auth_extension.h" #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/network_state_informer.h" @@ -148,6 +149,9 @@ class EnrollmentScreenHandler scoped_ptr histogram_helper_; + // GAIA extension loader. + scoped_ptr auth_extension_; + base::WeakPtrFactory weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(EnrollmentScreenHandler); diff --git a/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.cc index f616b604efda8..49717568c1247 100644 --- a/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.cc @@ -97,7 +97,6 @@ void ResetScreenHandler::ChooseAndApplyShowScenario() { switches::kFirstExecAfterBoot); reboot_was_requested_ = false; - rollback_available_ = false; preparing_for_rollback_ = false; if (!restart_required_) // First exec after boot. reboot_was_requested_ = prefs->GetBoolean(prefs::kFactoryResetRequested); @@ -106,19 +105,17 @@ void ResetScreenHandler::ChooseAndApplyShowScenario() { switches::kDisableRollbackOption)) { rollback_available_ = false; ShowWithParams(); - } else if (!restart_required_ && reboot_was_requested_) { - // First exec after boot. + } else if (restart_required_) { + // Will require restart. + ShowWithParams(); + } else { chromeos::DBusThreadManager::Get()->GetUpdateEngineClient()-> CanRollbackCheck(base::Bind(&ResetScreenHandler::OnRollbackCheck, weak_ptr_factory_.GetWeakPtr())); - } else { - // Will require restart. - ShowWithParams(); } } void ResetScreenHandler::Hide() { - DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this); } void ResetScreenHandler::SetDelegate(Delegate* delegate) { diff --git a/chrome/browser/ui/webui/net_internals/net_internals_ui.cc b/chrome/browser/ui/webui/net_internals/net_internals_ui.cc index 09e64c33aa790..89d4ce3d01998 100644 --- a/chrome/browser/ui/webui/net_internals/net_internals_ui.cc +++ b/chrome/browser/ui/webui/net_internals/net_internals_ui.cc @@ -663,8 +663,10 @@ void NetInternalsMessageHandler::OnGetPrerenderInfo( void NetInternalsMessageHandler::OnGetHistoricNetworkStats( const base::ListValue* list) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + Profile* profile = Profile::FromWebUI(web_ui()); base::Value* historic_network_info = - ChromeNetworkDelegate::HistoricNetworkStatsInfoToValue(); + ChromeNetworkDelegate::HistoricNetworkStatsInfoToValue( + profile->GetPrefs()); SendJavascriptCommand("receivedHistoricNetworkStats", historic_network_info); } diff --git a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc index da1e608329aa4..c6da4d716156f 100644 --- a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc +++ b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc @@ -83,7 +83,7 @@ const char kLearnMoreGuestSessionUrl[] = #if defined(OS_CHROMEOS) "https://www.google.com/support/chromeos/bin/answer.py?answer=1057090"; #else - "https://support.google.com/chrome/answer/95464#guest"; + "https://support.google.com/chrome/?p=ui_guest"; #endif std::string SkColorToRGBAString(SkColor color) { diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc index 1fa9831ac0698..7d9e944f4f708 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc +++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc @@ -266,6 +266,8 @@ content::WebUIDataSource* CreatePrintPreviewUISource() { IDS_PRINT_PREVIEW_MEDIA_SIZE_LABEL); source->AddLocalizedString("dpiLabel", IDS_PRINT_PREVIEW_DPI_LABEL); source->AddLocalizedString("dpiItemLabel", IDS_PRINT_PREVIEW_DPI_ITEM_LABEL); + source->AddLocalizedString("nonIsotropicDpiItemLabel", + IDS_PRINT_PREVIEW_NON_ISOTROPIC_DPI_ITEM_LABEL); source->AddLocalizedString("destinationSearchTitle", IDS_PRINT_PREVIEW_DESTINATION_SEARCH_TITLE); source->AddLocalizedString("accountSelectTitle", diff --git a/chrome/browser/upgrade_detector_impl.cc b/chrome/browser/upgrade_detector_impl.cc index bc0e4c78404b1..108f3ab1718d2 100644 --- a/chrome/browser/upgrade_detector_impl.cc +++ b/chrome/browser/upgrade_detector_impl.cc @@ -134,12 +134,10 @@ void DetectUpdatability(const base::Closure& callback_task, bool* is_auto_update_enabled) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - base::string16 app_guid = installer::GetAppGuidForUpdates(IsSystemInstall()); - DCHECK(!app_guid.empty()); // Don't try to turn on autoupdate when we failed previously. if (is_auto_update_enabled) { *is_auto_update_enabled = - GoogleUpdateSettings::AreAutoupdatesEnabled(app_guid); + GoogleUpdateSettings::AreAutoupdatesEnabled(); } *is_unstable_channel = IsUnstableChannel(); BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback_task); diff --git a/chrome/browser/web_applications/web_app_win.cc b/chrome/browser/web_applications/web_app_win.cc index e9688bd17a1ab..00f7ac23d02b6 100644 --- a/chrome/browser/web_applications/web_app_win.cc +++ b/chrome/browser/web_applications/web_app_win.cc @@ -618,7 +618,8 @@ bool CreatePlatformShortcuts( return false; } - if (switches::kEnableAppsFileAssociations) { + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableAppsFileAssociations)) { CreateFileAssociationsForApp( shortcut_info.extension_id, shortcut_info.title, shortcut_info.profile_path, file_handlers_info); diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 98ba5225b4190..44bad0dbedc24 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1049,6 +1049,8 @@ 'browser/safe_browsing/safe_browsing_tab_observer.h', 'browser/safe_browsing/srt_global_error_win.cc', 'browser/safe_browsing/srt_global_error_win.h', + 'browser/search/contextual_search_policy_handler_android.cc', + 'browser/search/contextual_search_policy_handler_android.h', 'browser/search/contextual_search_promo_source_android.cc', 'browser/search/contextual_search_promo_source_android.h', 'browser/search/iframe_source.cc', @@ -2207,6 +2209,8 @@ 'browser/first_run/try_chrome_dialog_view.cc', 'browser/first_run/try_chrome_dialog_view.h', 'browser/first_run/upgrade_util.cc', + 'browser/google/did_run_updater_win.cc', + 'browser/google/did_run_updater_win.h', 'browser/hang_monitor/hang_crash_dump_win.cc', 'browser/hang_monitor/hang_crash_dump_win.h', 'browser/hang_monitor/hung_plugin_action.cc', @@ -2766,6 +2770,7 @@ 'android/java/src/org/chromium/chrome/browser/JavascriptAppModalDialog.java', 'android/java/src/org/chromium/chrome/browser/NavigationPopup.java', 'android/java/src/org/chromium/chrome/browser/net/spdyproxy/DataReductionProxySettings.java', + 'android/java/src/org/chromium/chrome/browser/NotificationUIManager.java', 'android/java/src/org/chromium/chrome/browser/omnibox/AnswersImage.java', 'android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteController.java', 'android/java/src/org/chromium/chrome/browser/omnibox/OmniboxPrerender.java', @@ -3377,6 +3382,12 @@ '<(allocator_target)', ], }], + ['branding!="Chrome"', { + 'sources!': [ + 'browser/google/did_run_updater_win.cc', + 'browser/google/did_run_updater_win.h', + ], + }], ], }, { # 'OS!="win" 'sources': [ '<@(chrome_browser_non_win_sources)' ], diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi index 58b1acc795886..81c6d344af9cf 100644 --- a/chrome/chrome_browser_ui.gypi +++ b/chrome/chrome_browser_ui.gypi @@ -301,7 +301,7 @@ 'browser/ui/cocoa/browser_window_layout.mm', 'browser/ui/cocoa/browser_window_controller_private.h', 'browser/ui/cocoa/browser_window_controller_private.mm', - 'browser/ui/cocoa/browser_window_factory_cocoa.mm', + 'browser/ui/cocoa/browser_window_factory.mm', 'browser/ui/cocoa/browser_window_utils.h', 'browser/ui/cocoa/browser_window_utils.mm', 'browser/ui/cocoa/bubble_combobox.h', @@ -804,6 +804,8 @@ 'browser/ui/passwords/manage_passwords_icon.h', 'browser/ui/passwords/manage_passwords_ui_controller.cc', 'browser/ui/passwords/manage_passwords_ui_controller.h', + 'browser/ui/passwords/password_bubble_experiment.cc', + 'browser/ui/passwords/password_bubble_experiment.h', 'browser/ui/passwords/password_manager_presenter.cc', 'browser/ui/passwords/password_manager_presenter.h', 'browser/ui/passwords/password_ui_view.h', @@ -2006,11 +2008,9 @@ 'browser/ui/views/first_run_bubble.cc', 'browser/ui/views/first_run_bubble.h', 'browser/ui/views/frame/browser_frame.cc', - 'browser/ui/views/frame/browser_frame.h', 'browser/ui/views/frame/browser_frame_common_win.cc', 'browser/ui/views/frame/browser_frame_common_win.h', - 'browser/ui/views/frame/browser_frame_mac.h', - 'browser/ui/views/frame/browser_frame_mac.mm', + 'browser/ui/views/frame/browser_frame.h', 'browser/ui/views/frame/browser_non_client_frame_view.cc', 'browser/ui/views/frame/browser_non_client_frame_view_factory_aura.cc', 'browser/ui/views/frame/browser_non_client_frame_view.h', @@ -2023,7 +2023,6 @@ 'browser/ui/views/frame/browser_view_layout.cc', 'browser/ui/views/frame/browser_view_layout_delegate.h', 'browser/ui/views/frame/browser_view_layout.h', - 'browser/ui/views/frame/browser_window_factory.cc', 'browser/ui/views/frame/browser_window_property_manager_win.cc', 'browser/ui/views/frame/browser_window_property_manager_win.h', 'browser/ui/views/frame/contents_layout_manager.cc', @@ -2031,8 +2030,7 @@ 'browser/ui/views/frame/contents_web_view.cc', 'browser/ui/views/frame/contents_web_view.h', 'browser/ui/views/frame/immersive_mode_controller.cc', - 'browser/ui/views/frame/immersive_mode_controller_factory_ash.cc', - 'browser/ui/views/frame/immersive_mode_controller_factory_mac.cc', + 'browser/ui/views/frame/immersive_mode_controller_factory.cc', 'browser/ui/views/frame/immersive_mode_controller.h', 'browser/ui/views/frame/immersive_mode_controller_stub.cc', 'browser/ui/views/frame/immersive_mode_controller_stub.h', @@ -2041,7 +2039,6 @@ 'browser/ui/views/frame/native_browser_frame_factory.cc', 'browser/ui/views/frame/native_browser_frame_factory.h', 'browser/ui/views/frame/native_browser_frame_factory_chromeos.cc', - 'browser/ui/views/frame/native_browser_frame_factory_mac.cc', 'browser/ui/views/frame/native_browser_frame.h', 'browser/ui/views/frame/opaque_browser_frame_view_layout.cc', 'browser/ui/views/frame/opaque_browser_frame_view_layout_delegate.h', @@ -2803,15 +2800,7 @@ ['use_ash == 1', { 'sources': [ '<@(chrome_browser_ui_ash_views_sources)' ], }], - ['OS=="mac"', { - 'conditions': [ - ['mac_views_browser==1', { - 'sources!': [ 'browser/ui/cocoa/browser_window_factory_cocoa.mm', ], - }, { - 'sources!': [ 'browser/ui/views/frame/browser_window_factory.cc', ], - }], - ], - }, { + ['OS!="mac"', { 'sources': [ '<@(chrome_browser_ui_views_non_mac_sources)' ], 'dependencies': [ '<(DEPTH)/extensions/components/extensions_components.gyp:native_app_window', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 78b08f0579c65..430201e9f9575 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1218,6 +1218,7 @@ 'browser/sync/test/integration/single_client_backup_rollback_test.cc', 'browser/sync/test/integration/single_client_bookmarks_sync_test.cc', 'browser/sync/test/integration/single_client_dictionary_sync_test.cc', + 'browser/sync/test/integration/single_client_directory_sync_test.cc', 'browser/sync/test/integration/single_client_extensions_sync_test.cc', 'browser/sync/test/integration/single_client_passwords_sync_test.cc', 'browser/sync/test/integration/single_client_preferences_sync_test.cc', diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index f774021432188..eb5ae7d3f6b24 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi @@ -696,6 +696,7 @@ 'browser/safe_browsing/safe_browsing_store_unittest.cc', 'browser/safe_browsing/safe_browsing_util_unittest.cc', 'browser/safe_browsing/two_phase_uploader_unittest.cc', + 'browser/search/contextual_search_policy_handler_android_unittest.cc', 'browser/search/hotword_service_unittest.cc', 'browser/search/iframe_source_unittest.cc', 'browser/search/instant_service_unittest.cc', @@ -875,6 +876,7 @@ 'browser/thumbnails/thumbnail_service_unittest.cc', 'browser/translate/translate_manager_render_view_host_unittest.cc', 'browser/translate/translate_service_unittest.cc', + 'browser/ui/android/tab_model/tab_model_list_unittest.cc', 'browser/ui/android/tab_model/tab_model_unittest.cc', 'browser/ui/app_list/app_list_positioner_unittest.cc', 'browser/ui/app_list/app_list_service_mac_unittest.mm', @@ -1145,6 +1147,7 @@ 'browser/ui/passwords/manage_passwords_bubble_model_unittest.cc', 'browser/ui/passwords/manage_passwords_icon_mock.cc', 'browser/ui/passwords/manage_passwords_ui_controller_unittest.cc', + 'browser/ui/passwords/password_bubble_experiment_unittest.cc', 'browser/ui/passwords/password_manager_presenter_unittest.cc', 'browser/ui/search/instant_page_unittest.cc', 'browser/ui/search/instant_search_prerenderer_unittest.cc', @@ -1325,6 +1328,7 @@ 'common/favicon/favicon_url_parser_unittest.cc', 'common/importer/firefox_importer_utils_unittest.cc', 'common/ini_parser_unittest.cc', + 'common/instant_types_unittest.cc', 'common/mac/cfbundle_blocker_unittest.mm', 'common/mac/mock_launchd.cc', 'common/mac/mock_launchd.h', diff --git a/chrome/common/OWNERS b/chrome/common/OWNERS index e2dfba297df2d..dfa981683dc66 100644 --- a/chrome/common/OWNERS +++ b/chrome/common/OWNERS @@ -36,9 +36,9 @@ per-file spellcheck_result.h=rlp@chromium.org per-file spellcheck_result.h=rouslan@chromium.org # Instant/Search files. -per-file instant_types.*=kmadhusu@chromium.org -per-file instant_types.*=jered@chromium.org -per-file instant_types.*=samarth@chromium.org +per-file instant_types*=kmadhusu@chromium.org +per-file instant_types*=jered@chromium.org +per-file instant_types*=samarth@chromium.org per-file search_types.*=kmadhusu@chromium.org per-file search_types.*=jered@chromium.org per-file search_types.*=samarth@chromium.org diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json index 1f4a968b6c742..f17470e87f8e2 100644 --- a/chrome/common/extensions/api/_permission_features.json +++ b/chrome/common/extensions/api/_permission_features.json @@ -269,7 +269,8 @@ "BD8781D757D830FC2E85470A1B6E8A718B7EE0D9", // http://crbug.com/407693 "4AC2B6C63C6480D150DFDA13E4A5956EB1D0DDBB", // http://crbug.com/407693 "81986D4F846CEDDDB962643FA501D1780DD441BB", // http://crbug.com/407693 - "FF78670081967CE21DB86A04AD94A0498F01E20A" // http://crbug.com/409192 + "FF78670081967CE21DB86A04AD94A0498F01E20A", // http://crbug.com/409192 + "05EBA3051DFCA6AF17070AEE5FE8C66322FF4738" // http://crbug.com/431978 ] } ], diff --git a/chrome/common/extensions/api/automation.idl b/chrome/common/extensions/api/automation.idl index 9da10e0121c2b..920af3f2b7091 100644 --- a/chrome/common/extensions/api/automation.idl +++ b/chrome/common/extensions/api/automation.idl @@ -46,6 +46,7 @@ show, textChanged, textSelectionChanged, + treeChanged, valueChanged }; diff --git a/chrome/common/extensions/api/file_manager_private.idl b/chrome/common/extensions/api/file_manager_private.idl index a8c92bba07086..a1bad67918f1f 100644 --- a/chrome/common/extensions/api/file_manager_private.idl +++ b/chrome/common/extensions/api/file_manager_private.idl @@ -458,6 +458,10 @@ dictionary DriveConnectionState { // Reasons of offline. DOMString? reason; + + // Whether the device has a cellular network access or not. i.e. the |type| + // can be 'metered' or not. + boolean hasCellularNetworkAccess; }; // Device event dispatched to listeners of onDeviceChaged. See also diff --git a/chrome/common/instant_types.cc b/chrome/common/instant_types.cc index 5d199ae46de6f..4dca3a53501e4 100644 --- a/chrome/common/instant_types.cc +++ b/chrome/common/instant_types.cc @@ -4,6 +4,19 @@ #include "chrome/common/instant_types.h" +#include "base/strings/utf_string_conversions.h" +#include "net/base/escape.h" + +namespace { + +std::string GetComponent(const std::string& url, + const url::Component component) { + return (component.len > 0) ? url.substr(component.begin, component.len) : + std::string(); +} + +} // namespace + InstantSuggestion::InstantSuggestion() { } @@ -68,3 +81,50 @@ bool ThemeBackgroundInfo::operator==(const ThemeBackgroundInfo& rhs) const { has_attribution == rhs.has_attribution && logo_alternate == rhs.logo_alternate; } + +const char kSearchQueryKey[] = "q"; +const char kOriginalQueryKey[] = "oq"; +const char kRLZParameterKey[] = "rlz"; +const char kInputEncodingKey[] = "ie"; +const char kAssistedQueryStatsKey[] = "aqs"; + +EmbeddedSearchRequestParams::EmbeddedSearchRequestParams() { +} + +EmbeddedSearchRequestParams::EmbeddedSearchRequestParams(const GURL& url) { + const std::string& url_params(url.query()); + url::Component query, key, value; + query.len = static_cast(url_params.size()); + + const net::UnescapeRule::Type unescape_rules = + net::UnescapeRule::CONTROL_CHARS | net::UnescapeRule::SPACES | + net::UnescapeRule::URL_SPECIAL_CHARS | net::UnescapeRule::NORMAL | + net::UnescapeRule::REPLACE_PLUS_WITH_SPACE; + + while (url::ExtractQueryKeyValue(url_params.c_str(), &query, &key, &value)) { + if (!key.is_nonempty()) + continue; + + std::string key_param(GetComponent(url_params, key)); + std::string value_param(GetComponent(url_params, value)); + if (key_param == kSearchQueryKey) { + search_query = base::UTF8ToUTF16(net::UnescapeURLComponent( + value_param, unescape_rules)); + } else if (key_param == kOriginalQueryKey) { + original_query = base::UTF8ToUTF16(net::UnescapeURLComponent( + value_param, unescape_rules)); + } else if (key_param == kRLZParameterKey) { + rlz_parameter_value = net::UnescapeAndDecodeUTF8URLComponent( + value_param, net::UnescapeRule::NORMAL); + } else if (key_param == kInputEncodingKey) { + input_encoding = net::UnescapeAndDecodeUTF8URLComponent( + value_param, net::UnescapeRule::NORMAL); + } else if (key_param == kAssistedQueryStatsKey) { + assisted_query_stats = net::UnescapeAndDecodeUTF8URLComponent( + value_param, net::UnescapeRule::NORMAL); + } + } +} + +EmbeddedSearchRequestParams::~EmbeddedSearchRequestParams() { +} diff --git a/chrome/common/instant_types.h b/chrome/common/instant_types.h index e482a52a8946a..bc33f89aac5c9 100644 --- a/chrome/common/instant_types.h +++ b/chrome/common/instant_types.h @@ -131,4 +131,40 @@ struct InstantMostVisitedItem { typedef std::pair InstantMostVisitedItemIDPair; +// Embedded search request logging stats params. +extern const char kSearchQueryKey[]; +extern const char kOriginalQueryKey[]; +extern const char kRLZParameterKey[]; +extern const char kInputEncodingKey[]; +extern const char kAssistedQueryStatsKey[]; + +// A wrapper to hold embedded search request params. Used to tell the server +// about the search query logging stats at the query submission time. +struct EmbeddedSearchRequestParams { + EmbeddedSearchRequestParams(); + // Extracts the request params from the |url| and initializes the member + // variables. + explicit EmbeddedSearchRequestParams(const GURL& url); + ~EmbeddedSearchRequestParams(); + + // Submitted search query. + base::string16 search_query; + + // User typed query. + base::string16 original_query; + + // RLZ parameter. + base::string16 rlz_parameter_value; + + // Character input encoding type. + base::string16 input_encoding; + + // The optional assisted query stats, aka AQS, used for logging purposes. + // This string contains impressions of all autocomplete matches shown + // at the query submission time. For privacy reasons, we require the + // search provider to support HTTPS protocol in order to receive the AQS + // param. + // For more details, see http://goto.google.com/binary-clients-logging. + base::string16 assisted_query_stats; +}; #endif // CHROME_COMMON_INSTANT_TYPES_H_ diff --git a/chrome/common/instant_types_unittest.cc b/chrome/common/instant_types_unittest.cc new file mode 100644 index 0000000000000..47ebebdfd7fa9 --- /dev/null +++ b/chrome/common/instant_types_unittest.cc @@ -0,0 +1,69 @@ +// 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 "chrome/common/instant_types.h" + +#include "base/strings/utf_string_conversions.h" +#include "testing/gtest/include/gtest/gtest.h" + +struct TestData { + const char* search_request_url; + const char* expected_search_query; + const char* expected_original_query; + const char* expected_rlz_param; + const char* expected_input_encoding; + const char* expected_assisted_query_stats; +}; + +TEST(EmbeddedSearchRequestParams, ExtractParams) { + TestData cases[] = { + {"https://foo/search?q=google&oq=g&rlz=30ls&ie=utf-8&aqs=chrome..6l5.j04", + "google", + "g", + "30ls", + "utf-8", + "chrome..6l5.j04" + }, + // Do not populate "rlz" param. + {"https://foo/search?q=google%20j&oq=g&ie=utf-8&aqs=chrome.2.65.j04", + "google j", + "g", + "", + "utf-8", + "chrome.2.65.j04" + }, + // Unescape search query. + {"https://foo/search?q=google+j&oq=g&rlz=30&ie=utf-8&aqs=chrome.2.65.j04", + "google j", + "g", + "30", + "utf-8", + "chrome.2.65.j04" + }, + // Unescape original query. + {"https://foo/search?q=g+j%20j&oq=g+j&rlz=30&ie=utf-8&aqs=chrome.2.65.j04", + "g j j", + "g j", + "30", + "utf-8", + "chrome.2.65.j04" + }, + }; + + for (size_t i = 0; i < arraysize(cases); ++i) { + EmbeddedSearchRequestParams params(GURL(cases[i].search_request_url)); + EXPECT_EQ(cases[i].expected_search_query, + base::UTF16ToASCII(params.search_query)) << "For index: " << i; + EXPECT_EQ(cases[i].expected_original_query, + base::UTF16ToASCII(params.original_query)) << "For index: " << i; + EXPECT_EQ(cases[i].expected_rlz_param, + base::UTF16ToASCII(params.rlz_parameter_value)) << + "For index: " << i; + EXPECT_EQ(cases[i].expected_input_encoding, + base::UTF16ToASCII(params.input_encoding)) << "For index: " << i; + EXPECT_EQ(cases[i].expected_assisted_query_stats, + base::UTF16ToASCII(params.assisted_query_stats)) << + "For index: " << i; + } +} diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 2c2d7d418250b..fef44779b79ca 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -2279,4 +2279,14 @@ const char kBrowserAddPersonEnabled[] = "profile.add_person_enabled"; // A dictionary that maps user id to hardlock state. const char kEasyUnlockHardlockState[] = "easy_unlock.hardlock_state"; +// The beginning of time span when we count user's "Nope" for the password +// bubble. +const char kPasswordBubbleTimeStamp[] = "password_bubble.timestamp"; + +// The count of user's "Nope" for the password bubble. +const char kPasswordBubbleNopesCount[] = "password_bubble.nopes"; + +// Last user's interaction with the password bubble. +const char kPasswordBubbleLastInteractions[] = "password_bubble.interactions"; + } // namespace prefs diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 01a0089fb9bf2..214a3b59cf0d1 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -805,6 +805,10 @@ extern const char kBrowserAddPersonEnabled[]; extern const char kEasyUnlockHardlockState[]; +extern const char kPasswordBubbleTimeStamp[]; +extern const char kPasswordBubbleNopesCount[]; +extern const char kPasswordBubbleLastInteractions[]; + } // namespace prefs #endif // CHROME_COMMON_PREF_NAMES_H_ diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h index 8bba1bcbc034b..1d5b491025433 100644 --- a/chrome/common/render_messages.h +++ b/chrome/common/render_messages.h @@ -125,6 +125,14 @@ IPC_STRUCT_TRAITS_BEGIN(ContentSettingPatternSource) IPC_STRUCT_TRAITS_MEMBER(incognito) IPC_STRUCT_TRAITS_END() +IPC_STRUCT_TRAITS_BEGIN(EmbeddedSearchRequestParams) + IPC_STRUCT_TRAITS_MEMBER(search_query) + IPC_STRUCT_TRAITS_MEMBER(original_query) + IPC_STRUCT_TRAITS_MEMBER(rlz_parameter_value) + IPC_STRUCT_TRAITS_MEMBER(input_encoding) + IPC_STRUCT_TRAITS_MEMBER(assisted_query_stats) +IPC_STRUCT_TRAITS_END() + IPC_STRUCT_TRAITS_BEGIN(InstantSuggestion) IPC_STRUCT_TRAITS_MEMBER(text) IPC_STRUCT_TRAITS_MEMBER(metadata) @@ -267,8 +275,9 @@ IPC_MESSAGE_ROUTED1(ChromeViewMsg_SearchBoxSetInputInProgress, IPC_MESSAGE_ROUTED1(ChromeViewMsg_SearchBoxSetSuggestionToPrefetch, InstantSuggestion /* suggestion */) -IPC_MESSAGE_ROUTED1(ChromeViewMsg_SearchBoxSubmit, - base::string16 /* value */) +IPC_MESSAGE_ROUTED2(ChromeViewMsg_SearchBoxSubmit, + base::string16 /* value */, + EmbeddedSearchRequestParams /* params */) IPC_MESSAGE_ROUTED1(ChromeViewMsg_SearchBoxThemeChanged, ThemeBackgroundInfo /* value */) diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc index b02be692ed797..70fb2d3b055d7 100644 --- a/chrome/installer/setup/setup_main.cc +++ b/chrome/installer/setup/setup_main.cc @@ -1207,16 +1207,7 @@ bool HandleNonInstallCmdLineOptions(const InstallationState& original_state, } } else if (cmd_line.HasSwitch(installer::switches::kReenableAutoupdates)) { // setup.exe has been asked to attempt to reenable updates for Chrome. - // Figure out whether we should do so for the multi binaries or the main - // Chrome product. - BrowserDistribution::Type dist_type = BrowserDistribution::CHROME_BROWSER; - if (installer_state->is_multi_install()) - dist_type = BrowserDistribution::CHROME_BINARIES; - - BrowserDistribution* dist = - BrowserDistribution::GetSpecificDistribution(dist_type); - bool updates_enabled = - GoogleUpdateSettings::ReenableAutoupdatesForApp(dist->GetAppGuid()); + bool updates_enabled = GoogleUpdateSettings::ReenableAutoupdates(); *exit_code = updates_enabled ? installer::REENABLE_UPDATES_SUCCEEDED : installer::REENABLE_UPDATES_FAILED; } else { diff --git a/chrome/installer/util/google_update_settings.cc b/chrome/installer/util/google_update_settings.cc index 3c4cba6662885..2bcd470856e1d 100644 --- a/chrome/installer/util/google_update_settings.cc +++ b/chrome/installer/util/google_update_settings.cc @@ -64,45 +64,49 @@ bool ReadGoogleUpdateStrKey(const wchar_t* const name, base::string16* value) { return true; } +// Writes |value| into a user-specific value in the key |name| under +// |app_reg_data|'s ClientStateMedium key in HKLM along with the aggregation +// method |aggregate|. This function is solely for use by system-level installs. +bool WriteGoogleUpdateAggregateNumKeyInternal( + const AppRegistrationData& app_reg_data, + const wchar_t* const name, + int value, + const wchar_t* const aggregate) { + DCHECK(aggregate); + DCHECK(GoogleUpdateSettings::IsSystemInstall()); + const REGSAM kAccess = KEY_SET_VALUE | KEY_WOW64_32KEY; + + // Machine installs require each OS user to write a unique key under a + // named key in HKLM as well as an "aggregation" function that describes + // how the values of multiple users are to be combined. + base::string16 uniquename; + if (!base::win::GetUserSidString(&uniquename)) { + NOTREACHED(); + return false; + } + + base::string16 reg_path(app_reg_data.GetStateMediumKey()); + reg_path.append(L"\\"); + reg_path.append(name); + RegKey key(HKEY_LOCAL_MACHINE, reg_path.c_str(), kAccess); + key.WriteValue(google_update::kRegAggregateMethod, aggregate); + return (key.WriteValue(uniquename.c_str(), value) == ERROR_SUCCESS); +} + // Updates a registry key |name| to be |value| for the given |app_reg_data|. -// If this is a |system_install|, then update the value under HKLM (istead of -// HKCU for user-installs) using a group of keys (one for each OS user) and also -// include the method to |aggregate| these values when reporting. bool WriteGoogleUpdateStrKeyInternal(const AppRegistrationData& app_reg_data, - bool system_install, const wchar_t* const name, - const base::string16& value, - const wchar_t* const aggregate) { + const base::string16& value) { const REGSAM kAccess = KEY_SET_VALUE | KEY_WOW64_32KEY; - if (system_install) { - DCHECK(aggregate); - // Machine installs require each OS user to write a unique key under a - // named key in HKLM as well as an "aggregation" function that describes - // how the values of multiple users are to be combined. - base::string16 uniquename; - if (!base::win::GetUserSidString(&uniquename)) { - NOTREACHED(); - return false; - } - - base::string16 reg_path(app_reg_data.GetStateMediumKey()); - reg_path.append(L"\\"); - reg_path.append(name); - RegKey key(HKEY_LOCAL_MACHINE, reg_path.c_str(), kAccess); - key.WriteValue(google_update::kRegAggregateMethod, aggregate); - return (key.WriteValue(uniquename.c_str(), value.c_str()) == ERROR_SUCCESS); - } else { - // User installs are easy: just write the values to HKCU tree. - RegKey key(HKEY_CURRENT_USER, app_reg_data.GetStateKey().c_str(), kAccess); - return (key.WriteValue(name, value.c_str()) == ERROR_SUCCESS); - } + RegKey key(HKEY_CURRENT_USER, app_reg_data.GetStateKey().c_str(), kAccess); + return (key.WriteValue(name, value.c_str()) == ERROR_SUCCESS); } bool WriteGoogleUpdateStrKey(const wchar_t* const name, const base::string16& value) { BrowserDistribution* dist = BrowserDistribution::GetDistribution(); return WriteGoogleUpdateStrKeyInternal( - dist->GetAppRegistrationData(), false, name, value, NULL); + dist->GetAppRegistrationData(), name, value); } bool ClearGoogleUpdateStrKey(const wchar_t* const name) { @@ -434,10 +438,8 @@ bool GoogleUpdateSettings::UpdateDidRunStateForApp( const AppRegistrationData& app_reg_data, bool did_run) { return WriteGoogleUpdateStrKeyInternal(app_reg_data, - false, // user level. google_update::kRegDidRunField, - did_run ? L"1" : L"0", - NULL); + did_run ? L"1" : L"0"); } bool GoogleUpdateSettings::UpdateDidRunState(bool did_run, bool system_level) { @@ -547,17 +549,31 @@ bool GoogleUpdateSettings::UpdateGoogleUpdateApKey( void GoogleUpdateSettings::UpdateProfileCounts(int profiles_active, int profiles_signedin) { BrowserDistribution* dist = BrowserDistribution::GetDistribution(); - bool system_install = IsSystemInstall(); - WriteGoogleUpdateStrKeyInternal(dist->GetAppRegistrationData(), - system_install, - google_update::kRegProfilesActive, - base::Int64ToString16(profiles_active), - L"sum()"); - WriteGoogleUpdateStrKeyInternal(dist->GetAppRegistrationData(), - system_install, - google_update::kRegProfilesSignedIn, - base::Int64ToString16(profiles_signedin), - L"sum()"); + // System-level installs must write into the ClientStateMedium key shared by + // all users. Special treatment is used to aggregate across those users. + if (IsSystemInstall()) { + // Write the counts as ints that get aggregated across all users via + // summation for system-level installs. + WriteGoogleUpdateAggregateNumKeyInternal( + dist->GetAppRegistrationData(), + google_update::kRegProfilesActive, + profiles_active, + L"sum()"); + WriteGoogleUpdateAggregateNumKeyInternal( + dist->GetAppRegistrationData(), + google_update::kRegProfilesSignedIn, + profiles_signedin, + L"sum()"); + } else { + // Write the counts as strings since no aggregation function is needed for + // user-level installs. + WriteGoogleUpdateStrKeyInternal(dist->GetAppRegistrationData(), + google_update::kRegProfilesActive, + base::IntToString16(profiles_active)); + WriteGoogleUpdateStrKeyInternal(dist->GetAppRegistrationData(), + google_update::kRegProfilesSignedIn, + base::IntToString16(profiles_signedin)); + } } int GoogleUpdateSettings::DuplicateGoogleUpdateSystemClientKey() { @@ -625,8 +641,8 @@ GoogleUpdateSettings::UpdatePolicy GoogleUpdateSettings::GetAppUpdatePolicy( } // static -bool GoogleUpdateSettings::AreAutoupdatesEnabled( - const base::string16& app_guid) { +bool GoogleUpdateSettings::AreAutoupdatesEnabled() { +#if defined(GOOGLE_CHROME_BUILD) // Check the auto-update check period override. If it is 0 or exceeds the // maximum timeout, then for all intents and purposes auto updates are // disabled. @@ -640,47 +656,78 @@ bool GoogleUpdateSettings::AreAutoupdatesEnabled( return false; } - UpdatePolicy policy = GetAppUpdatePolicy(app_guid, NULL); - return (policy == AUTOMATIC_UPDATES || policy == AUTO_UPDATES_ONLY); + // Auto updates are subtly broken when Chrome and the binaries have different + // overrides in place. If this Chrome cannot possibly be multi-install by + // virtue of being a side-by-side installation, simply check Chrome's policy. + BrowserDistribution* dist = BrowserDistribution::GetDistribution(); + UpdatePolicy app_policy = GetAppUpdatePolicy(dist->GetAppGuid(), nullptr); + if (InstallUtil::IsChromeSxSProcess()) + return app_policy == AUTOMATIC_UPDATES || app_policy == AUTO_UPDATES_ONLY; + + // Otherwise, check for consistency between Chrome and the binaries regardless + // of whether or not this Chrome is multi-install since the next update likely + // will attempt to migrate it to such. + BrowserDistribution* binaries = BrowserDistribution::GetSpecificDistribution( + BrowserDistribution::CHROME_BINARIES); + return (GetAppUpdatePolicy(binaries->GetAppGuid(), nullptr) == app_policy && + (app_policy == AUTOMATIC_UPDATES || app_policy == AUTO_UPDATES_ONLY)); +#else // defined(GOOGLE_CHROME_BUILD) + // Chromium does not auto update. + return false; +#endif // !defined(GOOGLE_CHROME_BUILD) } // static -bool GoogleUpdateSettings::ReenableAutoupdatesForApp( - const base::string16& app_guid) { +bool GoogleUpdateSettings::ReenableAutoupdates() { #if defined(GOOGLE_CHROME_BUILD) int needs_reset_count = 0; int did_reset_count = 0; + // Reset overrides for Chrome and for the binaries if this Chrome supports + // multi-install. + std::vector app_guids; + app_guids.push_back(BrowserDistribution::GetDistribution()->GetAppGuid()); + if (!InstallUtil::IsChromeSxSProcess()) { + app_guids.push_back(BrowserDistribution::GetSpecificDistribution( + BrowserDistribution::CHROME_BINARIES)->GetAppGuid()); + } + UpdatePolicy update_policy = kDefaultUpdatePolicy; RegKey policy_key; if (policy_key.Open(HKEY_LOCAL_MACHINE, kPoliciesKey, KEY_SET_VALUE | KEY_QUERY_VALUE) == ERROR_SUCCESS) { - // First check the app-specific override value and reset that if needed. - // Note that this intentionally sets the override to AUTOMATIC_UPDATES - // even if it was previously AUTO_UPDATES_ONLY. The thinking is that - // AUTOMATIC_UPDATES is marginally more likely to let a user update and this - // code is only called when a stuck user asks for updates. - base::string16 app_update_override(kUpdateOverrideValuePrefix); - app_update_override.append(app_guid); + // Set to true while app-specific overrides are present that allow automatic + // updates. When this is the case, the defaults are irrelevant and don't + // need to be checked or reset. + bool automatic_updates_allowed_by_overrides = true; DWORD value = 0; - bool has_app_update_override = - policy_key.ReadValueDW(app_update_override.c_str(), - &value) == ERROR_SUCCESS; - if (has_app_update_override && - (!GetUpdatePolicyFromDword(value, &update_policy) || - update_policy != GoogleUpdateSettings::AUTOMATIC_UPDATES)) { - ++needs_reset_count; - if (policy_key.WriteValue( - app_update_override.c_str(), - static_cast(GoogleUpdateSettings::AUTOMATIC_UPDATES)) == - ERROR_SUCCESS) { - ++did_reset_count; + for (const base::string16& app_guid : app_guids) { + // First check the app-specific override value and reset that if needed. + // Note that this intentionally sets the override to AUTOMATIC_UPDATES + // even if it was previously AUTO_UPDATES_ONLY. The thinking is that + // AUTOMATIC_UPDATES is marginally more likely to let a user update and + // this code is only called when a stuck user asks for updates. + base::string16 app_update_override(kUpdateOverrideValuePrefix); + app_update_override.append(app_guid); + if (policy_key.ReadValueDW(app_update_override.c_str(), + &value) != ERROR_SUCCESS) { + automatic_updates_allowed_by_overrides = false; + } else if (!GetUpdatePolicyFromDword(value, &update_policy) || + update_policy != GoogleUpdateSettings::AUTOMATIC_UPDATES) { + automatic_updates_allowed_by_overrides = false; + ++needs_reset_count; + if (policy_key.WriteValue( + app_update_override.c_str(), + static_cast(GoogleUpdateSettings::AUTOMATIC_UPDATES)) == + ERROR_SUCCESS) { + ++did_reset_count; + } } } - // If there was no app-specific override policy see if there's a global + // If there were no app-specific override policies, see if there's a global // policy preventing updates and delete it if so. - if (!has_app_update_override && + if (!automatic_updates_allowed_by_overrides && policy_key.ReadValueDW(kUpdatePolicyValue, &value) == ERROR_SUCCESS && (!GetUpdatePolicyFromDword(value, &update_policy) || update_policy != GoogleUpdateSettings::AUTOMATIC_UPDATES)) { @@ -706,7 +753,7 @@ bool GoogleUpdateSettings::ReenableAutoupdatesForApp( // For some reason we couldn't open the policy key with the desired // permissions to make changes (the most likely reason is that there is no // policy set). Simply return whether or not we think updates are enabled. - return AreAutoupdatesEnabled(app_guid); + return AreAutoupdatesEnabled(); } #endif diff --git a/chrome/installer/util/google_update_settings.h b/chrome/installer/util/google_update_settings.h index bc66431129f48..ea5a7d5878f9b 100644 --- a/chrome/installer/util/google_update_settings.h +++ b/chrome/installer/util/google_update_settings.h @@ -243,22 +243,24 @@ class GoogleUpdateSettings { static UpdatePolicy GetAppUpdatePolicy(const base::string16& app_guid, bool* is_overridden); - // Returns true if the app indicated by |app_guid| should be updated - // automatically by Google Update based on current autoupdate settings. This - // is distinct from GetAppUpdatePolicy which checks only a subset of things - // that can cause an app not to update. - static bool AreAutoupdatesEnabled(const base::string16& app_guid); - - // Attempts to reenable auto-updates for |app_guid| by removing - // any group policy settings that would block updates from occurring. This is - // a superset of the things checked by GetAppUpdatePolicy() as - // GetAppUpdatePolicy() does not check Omaha's AutoUpdateCheckPeriodMinutes - // setting which will be reset by this method. Will need to be called from an - // elevated process since those settings live in HKLM. Returns true if there - // is a reasonable belief that updates are not disabled by policy when this - // method returns, false otherwise. Note that for Chromium builds, this - // returns true since Chromium is assumed not to autoupdate. - static bool ReenableAutoupdatesForApp(const base::string16& app_guid); + // Returns true if Chrome should be updated automatically by Google Update + // based on current autoupdate settings. This is distinct from + // GetAppUpdatePolicy (which checks only the policy for a given app), as it + // checks for general Google Update configuration as well as multi-install + // Chrome. Note that for Chromium builds, this returns false since Chromium is + // assumed not to autoupdate. + static bool AreAutoupdatesEnabled(); + + // Attempts to reenable auto-updates for Chrome by removing any group policy + // settings that would block updates from occurring. This is a superset of the + // things checked by GetAppUpdatePolicy() as GetAppUpdatePolicy() does not + // check Omaha's AutoUpdateCheckPeriodMinutes setting which will be reset by + // this method. Will need to be called from an elevated process since those + // settings live in HKLM. Returns true if there is a reasonable belief that + // updates are not disabled by policy when this method returns, false + // otherwise. Note that for Chromium builds, this returns true since Chromium + // is assumed not to autoupdate. + static bool ReenableAutoupdates(); // Records UMA stats about Chrome's update policy. static void RecordChromeUpdatePolicyHistograms(); diff --git a/chrome/installer/util/google_update_settings_unittest.cc b/chrome/installer/util/google_update_settings_unittest.cc index 4504d162ab60c..3e7943f01cbaa 100644 --- a/chrome/installer/util/google_update_settings_unittest.cc +++ b/chrome/installer/util/google_update_settings_unittest.cc @@ -8,10 +8,14 @@ #include // For SHDeleteKey. #include "base/memory/scoped_ptr.h" +#include "base/path_service.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_path_override.h" #include "base/test/test_reg_util_win.h" #include "base/win/registry.h" +#include "base/win/win_util.h" #include "chrome/common/chrome_constants.h" +#include "chrome/installer/util/app_registration_data.h" #include "chrome/installer/util/browser_distribution.h" #include "chrome/installer/util/channel_info.h" #include "chrome/installer/util/fake_installation_state.h" @@ -35,6 +39,11 @@ const wchar_t kTestExperimentLabel[] = L"test_label_value"; class GoogleUpdateSettingsTest : public testing::Test { protected: virtual void SetUp() override { + base::FilePath program_files_path; + PathService::Get(base::DIR_PROGRAM_FILES, &program_files_path); + program_files_override_.reset(new base::ScopedPathOverride( + base::DIR_PROGRAM_FILES, program_files_path)); + registry_overrides_.OverrideRegistry(HKEY_LOCAL_MACHINE); registry_overrides_.OverrideRegistry(HKEY_CURRENT_USER); } @@ -297,6 +306,8 @@ class GoogleUpdateSettingsTest : public testing::Test { time_in_minutes) == ERROR_SUCCESS; } + // Keep Program Files path so InstallUtil::IsPerUserInstall doesn't crash. + scoped_ptr program_files_override_; registry_util::RegistryOverrideManager registry_overrides_; }; @@ -628,6 +639,113 @@ TEST_F(GoogleUpdateSettingsTest, GetAppUpdatePolicyNoOverride) { EXPECT_FALSE(is_overridden); } +TEST_F(GoogleUpdateSettingsTest, UpdateProfileCountsSystemInstall) { + // Pretend to be a system install for GoogleUpdateSettings::IsSystemInstall(). + base::FilePath program_files_path; + PathService::Get(base::DIR_PROGRAM_FILES, &program_files_path); + base::ScopedPathOverride dir_module_override(base::DIR_MODULE, + program_files_path); + + // No profile count keys present yet. + const base::string16& state_key = BrowserDistribution::GetDistribution()-> + GetAppRegistrationData().GetStateMediumKey(); + base::string16 num_profiles_path(state_key); + num_profiles_path.append(L"\\"); + num_profiles_path.append(google_update::kRegProfilesActive); + base::string16 num_signed_in_path(state_key); + num_signed_in_path.append(L"\\"); + num_signed_in_path.append(google_update::kRegProfilesSignedIn); + + EXPECT_EQ(ERROR_FILE_NOT_FOUND, + RegKey().Open(HKEY_LOCAL_MACHINE, + num_profiles_path.c_str(), + KEY_QUERY_VALUE)); + EXPECT_EQ(ERROR_FILE_NOT_FOUND, + RegKey().Open(HKEY_LOCAL_MACHINE, + num_signed_in_path.c_str(), + KEY_QUERY_VALUE)); + + // Show time! Write the values. + GoogleUpdateSettings::UpdateProfileCounts(3, 2); + + // Verify the keys were created. + EXPECT_EQ(ERROR_SUCCESS, + RegKey().Open(HKEY_LOCAL_MACHINE, + num_profiles_path.c_str(), + KEY_QUERY_VALUE)); + EXPECT_EQ(ERROR_SUCCESS, + RegKey().Open(HKEY_LOCAL_MACHINE, + num_signed_in_path.c_str(), + KEY_QUERY_VALUE)); + + base::string16 uniquename; + EXPECT_TRUE(base::win::GetUserSidString(&uniquename)); + + // Verify the values are accessible. + DWORD num_profiles = 0; + DWORD num_signed_in = 0; + base::string16 aggregate; + EXPECT_EQ( + ERROR_SUCCESS, + RegKey(HKEY_LOCAL_MACHINE, num_profiles_path.c_str(), + KEY_QUERY_VALUE).ReadValueDW(uniquename.c_str(), + &num_profiles)); + EXPECT_EQ( + ERROR_SUCCESS, + RegKey(HKEY_LOCAL_MACHINE, num_signed_in_path.c_str(), + KEY_QUERY_VALUE).ReadValueDW(uniquename.c_str(), + &num_signed_in)); + EXPECT_EQ( + ERROR_SUCCESS, + RegKey(HKEY_LOCAL_MACHINE, num_signed_in_path.c_str(), + KEY_QUERY_VALUE).ReadValue(google_update::kRegAggregateMethod, + &aggregate)); + + // Verify the correct values were written. + EXPECT_EQ(3, num_profiles); + EXPECT_EQ(2, num_signed_in); + EXPECT_EQ(L"sum()", aggregate); +} + +TEST_F(GoogleUpdateSettingsTest, UpdateProfileCountsUserInstall) { + // Unit tests never operate as an installed application, so will never + // be a system install. + + // No profile count values present yet. + const base::string16& state_key = BrowserDistribution::GetDistribution()-> + GetAppRegistrationData().GetStateKey(); + + EXPECT_EQ(ERROR_FILE_NOT_FOUND, + RegKey().Open(HKEY_CURRENT_USER, + state_key.c_str(), + KEY_QUERY_VALUE)); + + // Show time! Write the values. + GoogleUpdateSettings::UpdateProfileCounts(4, 1); + + // Verify the key was created. + EXPECT_EQ(ERROR_SUCCESS, + RegKey().Open(HKEY_CURRENT_USER, + state_key.c_str(), + KEY_QUERY_VALUE)); + + // Verify the values are accessible. + base::string16 num_profiles; + base::string16 num_signed_in; + EXPECT_EQ( + ERROR_SUCCESS, + RegKey(HKEY_CURRENT_USER, state_key.c_str(), KEY_QUERY_VALUE). + ReadValue(google_update::kRegProfilesActive, &num_profiles)); + EXPECT_EQ( + ERROR_SUCCESS, + RegKey(HKEY_CURRENT_USER, state_key.c_str(), KEY_QUERY_VALUE). + ReadValue(google_update::kRegProfilesSignedIn, &num_signed_in)); + + // Verify the correct values were written. + EXPECT_EQ(L"4", num_profiles); + EXPECT_EQ(L"1", num_signed_in); +} + #if defined(GOOGLE_CHROME_BUILD) // Test that the default override is returned if no app-specific override is @@ -759,86 +877,91 @@ TEST_F(GoogleUpdateSettingsTest, GetAppUpdatePolicyAppOverride) { } TEST_F(GoogleUpdateSettingsTest, PerAppUpdatesDisabledByPolicy) { + BrowserDistribution* dist = BrowserDistribution::GetDistribution(); EXPECT_TRUE( - SetUpdatePolicyForAppGuid(kTestProductGuid, + SetUpdatePolicyForAppGuid(dist->GetAppGuid(), GoogleUpdateSettings::UPDATES_DISABLED)); bool is_overridden = false; GoogleUpdateSettings::UpdatePolicy update_policy = - GoogleUpdateSettings::GetAppUpdatePolicy(kTestProductGuid, + GoogleUpdateSettings::GetAppUpdatePolicy(dist->GetAppGuid(), &is_overridden); EXPECT_TRUE(is_overridden); EXPECT_EQ(GoogleUpdateSettings::UPDATES_DISABLED, update_policy); - EXPECT_FALSE(GoogleUpdateSettings::AreAutoupdatesEnabled(kTestProductGuid)); + EXPECT_FALSE(GoogleUpdateSettings::AreAutoupdatesEnabled()); - EXPECT_TRUE( - GoogleUpdateSettings::ReenableAutoupdatesForApp(kTestProductGuid)); - update_policy = GoogleUpdateSettings::GetAppUpdatePolicy(kTestProductGuid, + EXPECT_TRUE(GoogleUpdateSettings::ReenableAutoupdates()); + update_policy = GoogleUpdateSettings::GetAppUpdatePolicy(dist->GetAppGuid(), &is_overridden); // Should still have a policy but now that policy should explicitly enable // updates. EXPECT_TRUE(is_overridden); EXPECT_EQ(GoogleUpdateSettings::AUTOMATIC_UPDATES, update_policy); - EXPECT_TRUE(GoogleUpdateSettings::AreAutoupdatesEnabled(kTestProductGuid)); + EXPECT_TRUE(GoogleUpdateSettings::AreAutoupdatesEnabled()); } TEST_F(GoogleUpdateSettingsTest, PerAppUpdatesEnabledWithGlobalDisabled) { - // Disable updates globally but enable them for our specific app (the app- - // specific setting should take precedence). + // Disable updates globally but enable them for Chrome (the app-specific + // setting should take precedence). + BrowserDistribution* dist = BrowserDistribution::GetDistribution(); + BrowserDistribution* binaries = BrowserDistribution::GetSpecificDistribution( + BrowserDistribution::CHROME_BINARIES); + EXPECT_TRUE( + SetUpdatePolicyForAppGuid(dist->GetAppGuid(), + GoogleUpdateSettings::AUTOMATIC_UPDATES)); EXPECT_TRUE( - SetUpdatePolicyForAppGuid(kTestProductGuid, + SetUpdatePolicyForAppGuid(binaries->GetAppGuid(), GoogleUpdateSettings::AUTOMATIC_UPDATES)); EXPECT_TRUE(SetGlobalUpdatePolicy(GoogleUpdateSettings::UPDATES_DISABLED)); // Make sure we read this as still having updates enabled. - EXPECT_TRUE(GoogleUpdateSettings::AreAutoupdatesEnabled(kTestProductGuid)); + EXPECT_TRUE(GoogleUpdateSettings::AreAutoupdatesEnabled()); // Make sure that the reset action returns true and is a no-op. - EXPECT_TRUE( - GoogleUpdateSettings::ReenableAutoupdatesForApp(kTestProductGuid)); + EXPECT_TRUE(GoogleUpdateSettings::ReenableAutoupdates()); + EXPECT_EQ(GoogleUpdateSettings::AUTOMATIC_UPDATES, + GetUpdatePolicyForAppGuid(dist->GetAppGuid())); EXPECT_EQ(GoogleUpdateSettings::AUTOMATIC_UPDATES, - GetUpdatePolicyForAppGuid(kTestProductGuid)); + GetUpdatePolicyForAppGuid(binaries->GetAppGuid())); EXPECT_EQ(GoogleUpdateSettings::UPDATES_DISABLED, GetGlobalUpdatePolicy()); } TEST_F(GoogleUpdateSettingsTest, GlobalUpdatesDisabledByPolicy) { + BrowserDistribution* dist = BrowserDistribution::GetDistribution(); EXPECT_TRUE(SetGlobalUpdatePolicy(GoogleUpdateSettings::UPDATES_DISABLED)); bool is_overridden = false; // The contract for GetAppUpdatePolicy states that |is_overridden| should be // set to false when updates are disabled on a non-app-specific basis. GoogleUpdateSettings::UpdatePolicy update_policy = - GoogleUpdateSettings::GetAppUpdatePolicy(kTestProductGuid, + GoogleUpdateSettings::GetAppUpdatePolicy(dist->GetAppGuid(), &is_overridden); EXPECT_FALSE(is_overridden); EXPECT_EQ(GoogleUpdateSettings::UPDATES_DISABLED, update_policy); - EXPECT_FALSE(GoogleUpdateSettings::AreAutoupdatesEnabled(kTestProductGuid)); + EXPECT_FALSE(GoogleUpdateSettings::AreAutoupdatesEnabled()); - EXPECT_TRUE( - GoogleUpdateSettings::ReenableAutoupdatesForApp(kTestProductGuid)); - update_policy = GoogleUpdateSettings::GetAppUpdatePolicy(kTestProductGuid, + EXPECT_TRUE(GoogleUpdateSettings::ReenableAutoupdates()); + update_policy = GoogleUpdateSettings::GetAppUpdatePolicy(dist->GetAppGuid(), &is_overridden); // Policy should now be to enable updates, |is_overridden| should still be // false. EXPECT_FALSE(is_overridden); EXPECT_EQ(GoogleUpdateSettings::AUTOMATIC_UPDATES, update_policy); - EXPECT_TRUE(GoogleUpdateSettings::AreAutoupdatesEnabled(kTestProductGuid)); + EXPECT_TRUE(GoogleUpdateSettings::AreAutoupdatesEnabled()); } TEST_F(GoogleUpdateSettingsTest, UpdatesDisabledByTimeout) { // Disable updates altogether. EXPECT_TRUE(SetUpdateTimeoutOverride(0)); - EXPECT_FALSE(GoogleUpdateSettings::AreAutoupdatesEnabled(kTestProductGuid)); - EXPECT_TRUE( - GoogleUpdateSettings::ReenableAutoupdatesForApp(kTestProductGuid)); - EXPECT_TRUE(GoogleUpdateSettings::AreAutoupdatesEnabled(kTestProductGuid)); + EXPECT_FALSE(GoogleUpdateSettings::AreAutoupdatesEnabled()); + EXPECT_TRUE(GoogleUpdateSettings::ReenableAutoupdates()); + EXPECT_TRUE(GoogleUpdateSettings::AreAutoupdatesEnabled()); // Set the update period to something unreasonable. EXPECT_TRUE(SetUpdateTimeoutOverride( GoogleUpdateSettings::kCheckPeriodOverrideMinutesMax + 1)); - EXPECT_FALSE(GoogleUpdateSettings::AreAutoupdatesEnabled(kTestProductGuid)); - EXPECT_TRUE( - GoogleUpdateSettings::ReenableAutoupdatesForApp(kTestProductGuid)); - EXPECT_TRUE(GoogleUpdateSettings::AreAutoupdatesEnabled(kTestProductGuid)); + EXPECT_FALSE(GoogleUpdateSettings::AreAutoupdatesEnabled()); + EXPECT_TRUE(GoogleUpdateSettings::ReenableAutoupdates()); + EXPECT_TRUE(GoogleUpdateSettings::AreAutoupdatesEnabled()); } TEST_F(GoogleUpdateSettingsTest, ExperimentsLabelHelperSystem) { diff --git a/chrome/renderer/resources/extensions/searchbox_api.js b/chrome/renderer/resources/extensions/searchbox_api.js index 2ddf81932f3c9..4b5ab3ae0afbe 100644 --- a/chrome/renderer/resources/extensions/searchbox_api.js +++ b/chrome/renderer/resources/extensions/searchbox_api.js @@ -17,6 +17,7 @@ if (!chrome.embeddedSearch) { native function GetDisplayInstantResults(); native function GetMostVisitedItemData(); native function GetQuery(); + native function GetSearchRequestParams(); native function GetRightToLeft(); native function GetStartMargin(); native function GetSuggestionToPrefetch(); @@ -37,6 +38,8 @@ if (!chrome.embeddedSearch) { this.__defineGetter__('startMargin', GetStartMargin); this.__defineGetter__('suggestion', GetSuggestionToPrefetch); this.__defineGetter__('value', GetQuery); + Object.defineProperty(this, 'requestParams', + { get: GetSearchRequestParams }); this.focus = function() { Focus(); diff --git a/chrome/renderer/searchbox/searchbox.cc b/chrome/renderer/searchbox/searchbox.cc index 7c898c5b27432..f639bfc9c5933 100644 --- a/chrome/renderer/searchbox/searchbox.cc +++ b/chrome/renderer/searchbox/searchbox.cc @@ -237,6 +237,10 @@ const ThemeBackgroundInfo& SearchBox::GetThemeBackgroundInfo() { return theme_info_; } +const EmbeddedSearchRequestParams& SearchBox::GetEmbeddedSearchRequestParams() { + return embedded_search_request_params_; +} + void SearchBox::Focus() { render_view()->Send(new ChromeViewHostMsg_FocusOmnibox( render_view()->GetRoutingID(), page_seq_no_, OMNIBOX_FOCUS_VISIBLE)); @@ -426,8 +430,10 @@ void SearchBox::OnSetSuggestionToPrefetch(const InstantSuggestion& suggestion) { } } -void SearchBox::OnSubmit(const base::string16& query) { +void SearchBox::OnSubmit(const base::string16& query, + const EmbeddedSearchRequestParams& params) { query_ = query; + embedded_search_request_params_ = params; if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { DVLOG(1) << render_view() << " OnSubmit"; extensions_v8::SearchBoxExtension::DispatchSubmit( @@ -463,6 +469,7 @@ GURL SearchBox::GetURLForMostVisitedItem(InstantRestrictedID item_id) const { void SearchBox::Reset() { query_.clear(); + embedded_search_request_params_ = EmbeddedSearchRequestParams(); suggestion_ = InstantSuggestion(); start_margin_ = 0; is_focused_ = false; diff --git a/chrome/renderer/searchbox/searchbox.h b/chrome/renderer/searchbox/searchbox.h index cf0ea52d61b5c..4b32c81ba1a69 100644 --- a/chrome/renderer/searchbox/searchbox.h +++ b/chrome/renderer/searchbox/searchbox.h @@ -86,6 +86,7 @@ class SearchBox : public content::RenderViewObserver, void Paste(const base::string16& text); const ThemeBackgroundInfo& GetThemeBackgroundInfo(); + const EmbeddedSearchRequestParams& GetEmbeddedSearchRequestParams(); // Sends ChromeViewHostMsg_SetVoiceSearchSupported to the browser. void SetVoiceSearchSupported(bool supported); @@ -129,7 +130,8 @@ class SearchBox : public content::RenderViewObserver, void OnSetDisplayInstantResults(bool display_instant_results); void OnSetInputInProgress(bool input_in_progress); void OnSetSuggestionToPrefetch(const InstantSuggestion& suggestion); - void OnSubmit(const base::string16& query); + void OnSubmit(const base::string16& query, + const EmbeddedSearchRequestParams& params); void OnThemeChanged(const ThemeBackgroundInfo& theme_info); void OnToggleVoiceSearch(); @@ -151,6 +153,7 @@ class SearchBox : public content::RenderViewObserver, InstantRestrictedIDCache most_visited_items_cache_; ThemeBackgroundInfo theme_info_; base::string16 query_; + EmbeddedSearchRequestParams embedded_search_request_params_; int start_margin_; InstantSuggestion suggestion_; diff --git a/chrome/renderer/searchbox/searchbox_extension.cc b/chrome/renderer/searchbox/searchbox_extension.cc index 612287b33774c..250915cc22f1f 100644 --- a/chrome/renderer/searchbox/searchbox_extension.cc +++ b/chrome/renderer/searchbox/searchbox_extension.cc @@ -383,6 +383,10 @@ class SearchBoxExtensionWrapper : public v8::Extension { // Returns true if the Searchbox itself is oriented right-to-left. static void GetRightToLeft(const v8::FunctionCallbackInfo& args); + // Gets the Embedded Search request params. Used for logging purposes. + static void GetSearchRequestParams( + const v8::FunctionCallbackInfo& args); + // Gets the start-edge margin to use with extended Instant. static void GetStartMargin(const v8::FunctionCallbackInfo& args); @@ -561,6 +565,8 @@ SearchBoxExtensionWrapper::GetNativeFunctionTemplate( return v8::FunctionTemplate::New(isolate, GetQuery); if (name->Equals(v8::String::NewFromUtf8(isolate, "GetRightToLeft"))) return v8::FunctionTemplate::New(isolate, GetRightToLeft); + if (name->Equals(v8::String::NewFromUtf8(isolate, "GetSearchRequestParams"))) + return v8::FunctionTemplate::New(isolate, GetSearchRequestParams); if (name->Equals(v8::String::NewFromUtf8(isolate, "GetStartMargin"))) return v8::FunctionTemplate::New(isolate, GetStartMargin); if (name->Equals(v8::String::NewFromUtf8(isolate, "GetSuggestionToPrefetch"))) @@ -745,6 +751,39 @@ void SearchBoxExtensionWrapper::GetRightToLeft( args.GetReturnValue().Set(base::i18n::IsRTL()); } +// static +void SearchBoxExtensionWrapper::GetSearchRequestParams( + const v8::FunctionCallbackInfo& args) { + content::RenderView* render_view = GetRenderView(); + if (!render_view) return; + + const EmbeddedSearchRequestParams& params = + SearchBox::Get(render_view)->GetEmbeddedSearchRequestParams(); + v8::Isolate* isolate = args.GetIsolate(); + v8::Handle data = v8::Object::New(isolate); + if (!params.search_query.empty()) { + data->Set(v8::String::NewFromUtf8(isolate, kSearchQueryKey), + UTF16ToV8String(isolate, params.search_query)); + } + if (!params.original_query.empty()) { + data->Set(v8::String::NewFromUtf8(isolate, kOriginalQueryKey), + UTF16ToV8String(isolate, params.original_query)); + } + if (!params.rlz_parameter_value.empty()) { + data->Set(v8::String::NewFromUtf8(isolate, kRLZParameterKey), + UTF16ToV8String(isolate, params.rlz_parameter_value)); + } + if (!params.input_encoding.empty()) { + data->Set(v8::String::NewFromUtf8(isolate, kInputEncodingKey), + UTF16ToV8String(isolate, params.input_encoding)); + } + if (!params.assisted_query_stats.empty()) { + data->Set(v8::String::NewFromUtf8(isolate, kAssistedQueryStatsKey), + UTF16ToV8String(isolate, params.assisted_query_stats)); + } + args.GetReturnValue().Set(data); +} + // static void SearchBoxExtensionWrapper::GetStartMargin( const v8::FunctionCallbackInfo& args) { diff --git a/chrome/test/data/extensions/platform_apps/hidden/empty.html b/chrome/test/data/extensions/platform_apps/hidden/empty.html new file mode 100644 index 0000000000000..aabcd1b1e2f0b --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/hidden/empty.html @@ -0,0 +1 @@ + diff --git a/chrome/test/data/extensions/platform_apps/hidden/manifest.json b/chrome/test/data/extensions/platform_apps/hidden/manifest.json new file mode 100644 index 0000000000000..71a83d3743b53 --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/hidden/manifest.json @@ -0,0 +1,10 @@ +{ + "name": "Platform App Hidden", + "version": "1", + "manifest_version": 2, + "app": { + "background": { + "scripts": ["test.js"] + } + } +} diff --git a/chrome/test/data/extensions/platform_apps/hidden/test.js b/chrome/test/data/extensions/platform_apps/hidden/test.js new file mode 100644 index 0000000000000..c11022784fb68 --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/hidden/test.js @@ -0,0 +1,11 @@ +// 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. + +chrome.app.runtime.onLaunched.addListener(function() { + chrome.app.window.create('main.html', { + hidden: true, + }, function () { + chrome.test.sendMessage('Launched'); + }); +}); \ No newline at end of file diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json index 97ecbb04afc92..44380a731ae2f 100644 --- a/chrome/test/data/policy/policy_test_cases.json +++ b/chrome/test/data/policy/policy_test_cases.json @@ -353,6 +353,10 @@ ] }, + "ContextualSearchEnabled": { + "os": ["android"] + }, + "AutoFillEnabled": { "os": ["win", "linux", "mac", "chromeos"], "can_be_recommended": true, diff --git a/chromeos/chromeos.gyp b/chromeos/chromeos.gyp index 98ddfc33b0e6e..c7d613a8752c1 100644 --- a/chromeos/chromeos.gyp +++ b/chromeos/chromeos.gyp @@ -275,6 +275,8 @@ 'login/user_names.h', 'login_event_recorder.cc', 'login_event_recorder.h', + 'network/auto_connect_handler.cc', + 'network/auto_connect_handler.h', 'network/certificate_pattern.cc', 'network/certificate_pattern.h', 'network/client_cert_resolver.cc', @@ -423,6 +425,7 @@ 'ime/input_method_whitelist_unittest.cc', 'login/auth/key_unittest.cc', 'login/login_state_unittest.cc', + 'network/auto_connect_handler_unittest.cc', 'network/client_cert_resolver_unittest.cc', 'network/geolocation_handler_unittest.cc', 'network/host_resolver_impl_chromeos_unittest.cc', diff --git a/chromeos/dbus/fake_session_manager_client.cc b/chromeos/dbus/fake_session_manager_client.cc index c5fe549335d4a..b6d2d8ec01ecf 100644 --- a/chromeos/dbus/fake_session_manager_client.cc +++ b/chromeos/dbus/fake_session_manager_client.cc @@ -56,6 +56,12 @@ void FakeSessionManagerClient::StartSession(const std::string& user_email) { void FakeSessionManagerClient::StopSession() { } +void FakeSessionManagerClient::NotifySupervisedUserCreationStarted() { +} + +void FakeSessionManagerClient::NotifySupervisedUserCreationFinished() { +} + void FakeSessionManagerClient::StartDeviceWipe() { start_device_wipe_call_count_++; } diff --git a/chromeos/dbus/fake_session_manager_client.h b/chromeos/dbus/fake_session_manager_client.h index f69e262c3aa53..367f2d7d833a3 100644 --- a/chromeos/dbus/fake_session_manager_client.h +++ b/chromeos/dbus/fake_session_manager_client.h @@ -33,6 +33,8 @@ class FakeSessionManagerClient : public SessionManagerClient { virtual void RestartJob(int pid, const std::string& command_line) override; virtual void StartSession(const std::string& user_email) override; virtual void StopSession() override; + virtual void NotifySupervisedUserCreationStarted() override; + virtual void NotifySupervisedUserCreationFinished() override; virtual void StartDeviceWipe() override; virtual void RequestLockScreen() override; virtual void NotifyLockScreenShown() override; diff --git a/chromeos/dbus/mock_session_manager_client.h b/chromeos/dbus/mock_session_manager_client.h index c0e45310c9362..4e1ffbca0394d 100644 --- a/chromeos/dbus/mock_session_manager_client.h +++ b/chromeos/dbus/mock_session_manager_client.h @@ -26,6 +26,8 @@ class MockSessionManagerClient : public SessionManagerClient { MOCK_METHOD2(RestartJob, void(int, const std::string&)); MOCK_METHOD1(StartSession, void(const std::string&)); MOCK_METHOD0(StopSession, void(void)); + MOCK_METHOD0(NotifySupervisedUserCreationStarted, void(void)); + MOCK_METHOD0(NotifySupervisedUserCreationFinished, void(void)); MOCK_METHOD0(StartDeviceWipe, void(void)); MOCK_METHOD0(RequestLockScreen, void(void)); MOCK_METHOD0(NotifyLockScreenShown, void(void)); diff --git a/chromeos/dbus/session_manager_client.cc b/chromeos/dbus/session_manager_client.cc index 5a67ee8a55519..af81816538b7e 100644 --- a/chromeos/dbus/session_manager_client.cc +++ b/chromeos/dbus/session_manager_client.cc @@ -156,6 +156,16 @@ class SessionManagerClientImpl : public SessionManagerClient { login_manager::kSessionManagerHandleLockScreenDismissed); } + virtual void NotifySupervisedUserCreationStarted() override { + SimpleMethodCallToSessionManager( + login_manager::kSessionManagerHandleSupervisedUserCreationStarting); + } + + virtual void NotifySupervisedUserCreationFinished() override { + SimpleMethodCallToSessionManager( + login_manager::kSessionManagerHandleSupervisedUserCreationFinished); + } + virtual void RetrieveActiveSessions( const ActiveSessionsCallback& callback) override { dbus::MethodCall method_call( @@ -590,6 +600,8 @@ class SessionManagerClientStubImpl : public SessionManagerClient { virtual void RestartJob(int pid, const std::string& command_line) override {} virtual void StartSession(const std::string& user_email) override {} virtual void StopSession() override {} + virtual void NotifySupervisedUserCreationStarted() override {} + virtual void NotifySupervisedUserCreationFinished() override {} virtual void StartDeviceWipe() override {} virtual void RequestLockScreen() override { if (delegate_) diff --git a/chromeos/dbus/session_manager_client.h b/chromeos/dbus/session_manager_client.h index d4c07066e2deb..75d727762f329 100644 --- a/chromeos/dbus/session_manager_client.h +++ b/chromeos/dbus/session_manager_client.h @@ -89,6 +89,12 @@ class CHROMEOS_EXPORT SessionManagerClient : public DBusClient { // Notifies that the lock screen is dismissed. virtual void NotifyLockScreenDismissed() = 0; + // Notifies that supervised user creation have started. + virtual void NotifySupervisedUserCreationStarted() = 0; + + // Notifies that supervised user creation have finished. + virtual void NotifySupervisedUserCreationFinished() = 0; + // Map that is used to describe the set of active user sessions where |key| // is user_id and |value| is user_id_hash. typedef std::map ActiveSessionsMap; diff --git a/chromeos/ime/component_extension_ime_manager.cc b/chromeos/ime/component_extension_ime_manager.cc index 9a8cce1d507a4..6c7f0685b3eaa 100644 --- a/chromeos/ime/component_extension_ime_manager.cc +++ b/chromeos/ime/component_extension_ime_manager.cc @@ -59,6 +59,27 @@ const char* kLoginLayoutWhitelist[] = { "us(intl)" }; +// Gets the input method category according to the given input method id. +// This is used for sorting a list of input methods. +int GetInputMethodCategory(const std::string& id) { + const std::string engine_id = + chromeos::extension_ime_util::GetComponentIDByInputMethodID(id); + if (StartsWithASCII(engine_id, "xkb:", true)) + return 0; + if (StartsWithASCII(engine_id, "vkd_", true)) + return 1; + if (engine_id.find("-t-i0-") != std::string::npos && + !StartsWithASCII(engine_id, "zh-", true)) { + return 2; + } + return 3; +} + +bool InputMethodCompare(const input_method::InputMethodDescriptor& im1, + const input_method::InputMethodDescriptor& im2) { + return GetInputMethodCategory(im1.id()) < GetInputMethodCategory(im2.id()); +} + } // namespace ComponentExtensionEngine::ComponentExtensionEngine() { @@ -173,6 +194,7 @@ input_method::InputMethodDescriptors ime.input_view_url)); } } + std::stable_sort(result.begin(), result.end(), InputMethodCompare); return result; } diff --git a/chromeos/ime/component_extension_ime_manager_unittest.cc b/chromeos/ime/component_extension_ime_manager_unittest.cc index 9e8bdb3c19875..840f3c473d1d5 100644 --- a/chromeos/ime/component_extension_ime_manager_unittest.cc +++ b/chromeos/ime/component_extension_ime_manager_unittest.cc @@ -28,24 +28,24 @@ class ComponentExtensionIMEManagerTest : public testing::Test { ext1.path = base::FilePath("ext1_file_path"); ComponentExtensionEngine ext1_engine1; - ext1_engine1.engine_id = "ext1_engine1_engine_id"; + ext1_engine1.engine_id = "zh-t-i0-pinyin"; ext1_engine1.display_name = "ext1_engine_1_display_name"; - ext1_engine1.language_codes.push_back("en"); + ext1_engine1.language_codes.push_back("zh-CN"); ext1_engine1.layouts.push_back("us"); ext1.engines.push_back(ext1_engine1); ComponentExtensionEngine ext1_engine2; - ext1_engine2.engine_id = "ext1_engine2_engine_id"; + ext1_engine2.engine_id = "mozc_us"; ext1_engine2.display_name = "ext1_engine2_display_name"; - ext1_engine2.language_codes.push_back("en"); + ext1_engine2.language_codes.push_back("jp"); ext1_engine2.layouts.push_back("us"); ext1.engines.push_back(ext1_engine2); ComponentExtensionEngine ext1_engine3; - ext1_engine3.engine_id = "ext1_engine3_engine_id"; + ext1_engine3.engine_id = "xkb:ru::rus"; ext1_engine3.display_name = "ext1_engine3_display_name"; - ext1_engine3.language_codes.push_back("ja"); - ext1_engine3.layouts.push_back("us"); + ext1_engine3.language_codes.push_back("ru"); + ext1_engine3.layouts.push_back("ru"); ext1.engines.push_back(ext1_engine3); ime_list_.push_back(ext1); @@ -56,24 +56,24 @@ class ComponentExtensionIMEManagerTest : public testing::Test { ext2.path = base::FilePath("ext2_file_path"); ComponentExtensionEngine ext2_engine1; - ext2_engine1.engine_id = "ext2_engine1_engine_id"; + ext2_engine1.engine_id = "vkd_ru_phone_aatseel"; ext2_engine1.display_name = "ext2_engine_1_display_name"; - ext2_engine1.language_codes.push_back("en"); + ext2_engine1.language_codes.push_back("ru"); ext2_engine1.layouts.push_back("us"); ext2.engines.push_back(ext2_engine1); ComponentExtensionEngine ext2_engine2; - ext2_engine2.engine_id = "ext2_engine2_engine_id"; + ext2_engine2.engine_id = "vkd_vi_telex"; ext2_engine2.display_name = "ext2_engine2_display_name"; ext2_engine2.language_codes.push_back("hi"); ext2_engine2.layouts.push_back("us"); ext2.engines.push_back(ext2_engine2); ComponentExtensionEngine ext2_engine3; - ext2_engine3.engine_id = "ext2_engine3_engine_id"; + ext2_engine3.engine_id = "xkb:us::eng"; ext2_engine3.display_name = "ext2_engine3_display_name"; - ext2_engine3.language_codes.push_back("ja"); - ext2_engine3.layouts.push_back("jp"); + ext2_engine3.language_codes.push_back("us"); + ext2_engine3.layouts.push_back("us"); ext2.engines.push_back(ext2_engine3); ime_list_.push_back(ext2); @@ -191,6 +191,16 @@ TEST_F(ComponentExtensionIMEManagerTest, GetAllIMEAsInputMethodDescriptor) { total_ime_size += ime_list_[i].engines.size(); } EXPECT_EQ(total_ime_size, descriptors.size()); + + // Verify order + for (size_t i = 0; i < descriptors.size(); ++i) { + const input_method::InputMethodDescriptor& d = descriptors[i]; + if (i < 2) { + EXPECT_TRUE(d.id().find("xkb:") != std::string::npos); + } else if (i >= 2 && i < 4) { + EXPECT_TRUE(d.id().find("vkd_") != std::string::npos); + } + } } } // namespace diff --git a/chromeos/network/auto_connect_handler.cc b/chromeos/network/auto_connect_handler.cc new file mode 100644 index 0000000000000..37f0344fa1b9f --- /dev/null +++ b/chromeos/network/auto_connect_handler.cc @@ -0,0 +1,214 @@ +// 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 "chromeos/network/auto_connect_handler.h" + +#include + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/values.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/shill_service_client.h" +#include "chromeos/network/managed_network_configuration_handler.h" +#include "chromeos/network/network_event_log.h" +#include "chromeos/network/network_state.h" +#include "dbus/object_path.h" + +namespace chromeos { + +AutoConnectHandler::AutoConnectHandler() + : client_cert_resolver_(nullptr), + request_best_connection_pending_(false), + device_policy_applied_(false), + user_policy_applied_(false), + client_certs_resolved_(false), + applied_autoconnect_policy_(false) { +} + +AutoConnectHandler::~AutoConnectHandler() { + if (client_cert_resolver_) + client_cert_resolver_->RemoveObserver(this); + if (LoginState::IsInitialized()) + LoginState::Get()->RemoveObserver(this); + if (managed_configuration_handler_) + managed_configuration_handler_->RemoveObserver(this); +} + +void AutoConnectHandler::Init( + ClientCertResolver* client_cert_resolver, + NetworkConnectionHandler* network_connection_handler, + NetworkStateHandler* network_state_handler, + ManagedNetworkConfigurationHandler* managed_network_configuration_handler) { + if (LoginState::IsInitialized()) + LoginState::Get()->AddObserver(this); + + client_cert_resolver_ = client_cert_resolver; + if (client_cert_resolver_) + client_cert_resolver_->AddObserver(this); + + network_connection_handler_ = network_connection_handler; + if (network_connection_handler_) + network_connection_handler_->AddObserver(this); + + network_state_handler_ = network_state_handler; + + if (managed_network_configuration_handler) { + managed_configuration_handler_ = managed_network_configuration_handler; + managed_configuration_handler_->AddObserver(this); + } + + if (LoginState::IsInitialized()) + LoggedInStateChanged(); +} + +void AutoConnectHandler::LoggedInStateChanged() { + if (!LoginState::Get()->IsUserLoggedIn()) + return; + + // Disconnect before connecting, to ensure that we do not disconnect a network + // that we just connected. + DisconnectIfPolicyRequires(); + NET_LOG_DEBUG("RequestBestConnection", "User logged in"); + RequestBestConnection(); +} + +void AutoConnectHandler::ConnectToNetworkRequested( + const std::string& /*service_path*/) { + // Stop any pending request to connect to the best newtork. + request_best_connection_pending_ = false; +} + +void AutoConnectHandler::PoliciesChanged(const std::string& userhash) { + // Ignore user policies. + if (!userhash.empty()) + return; + DisconnectIfPolicyRequires(); +} + +void AutoConnectHandler::PoliciesApplied(const std::string& userhash) { + if (userhash.empty()) + device_policy_applied_ = true; + else + user_policy_applied_ = true; + + // Request to connect to the best network only if there is at least one + // managed network. Otherwise only process existing requests. + const ManagedNetworkConfigurationHandler::GuidToPolicyMap* managed_networks = + managed_configuration_handler_->GetNetworkConfigsFromPolicy(userhash); + DCHECK(managed_networks); + if (!managed_networks->empty()) { + NET_LOG_DEBUG("RequestBestConnection", "Policy applied"); + RequestBestConnection(); + } else { + CheckBestConnection(); + } +} + +void AutoConnectHandler::ResolveRequestCompleted( + bool network_properties_changed) { + client_certs_resolved_ = true; + + // Only request to connect to the best network if network properties were + // actually changed. Otherwise only process existing requests. + if (network_properties_changed) { + NET_LOG_DEBUG("RequestBestConnection", + "Client certificate patterns resolved"); + RequestBestConnection(); + } else { + CheckBestConnection(); + } +} + +void AutoConnectHandler::RequestBestConnection() { + request_best_connection_pending_ = true; + CheckBestConnection(); +} + +void AutoConnectHandler::CheckBestConnection() { + // Return immediately if there is currently no request pending to change to + // the best network. + if (!request_best_connection_pending_) + return; + + bool policy_application_running = + managed_configuration_handler_->IsAnyPolicyApplicationRunning(); + bool client_cert_resolve_task_running = + client_cert_resolver_->IsAnyResolveTaskRunning(); + VLOG(2) << "device policy applied: " << device_policy_applied_ + << "\nuser policy applied: " << user_policy_applied_ + << "\npolicy application running: " << policy_application_running + << "\nclient cert patterns resolved: " << client_certs_resolved_ + << "\nclient cert resolve task running: " + << client_cert_resolve_task_running; + if (!device_policy_applied_ || policy_application_running || + client_cert_resolve_task_running) { + return; + } + + if (LoginState::Get()->IsUserLoggedIn()) { + // Before changing connection after login, we wait at least for: + // - user policy applied at least once + // - client certificate patterns resolved + if (!user_policy_applied_ || !client_certs_resolved_) + return; + } + + request_best_connection_pending_ = false; + NET_LOG_EVENT("ConnectToBestWifiNetwork", ""); + network_state_handler_->ConnectToBestWifiNetwork(); +} + +void AutoConnectHandler::DisconnectIfPolicyRequires() { + if (applied_autoconnect_policy_ || !LoginState::Get()->IsUserLoggedIn()) + return; + + const base::DictionaryValue* global_network_config = + managed_configuration_handler_->GetGlobalConfigFromPolicy( + std::string() /* no username hash, device policy */); + + if (!global_network_config) + return; // Device policy is not set, yet. + + applied_autoconnect_policy_ = true; + + bool only_policy_autoconnect = false; + global_network_config->GetBooleanWithoutPathExpansion( + ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect, + &only_policy_autoconnect); + + if (only_policy_autoconnect) + DisconnectFromUnmanagedSharedWiFiNetworks(); +} + +void AutoConnectHandler::DisconnectFromUnmanagedSharedWiFiNetworks() { + NET_LOG_DEBUG("DisconnectFromUnmanagedSharedWiFiNetworks", ""); + + NetworkStateHandler::NetworkStateList networks; + network_state_handler_->GetVisibleNetworkListByType( + NetworkTypePattern::Wireless(), &networks); + for (const NetworkState* network : networks) { + if (!(network->IsConnectingState() || network->IsConnectedState())) + break; // Connected and connecting networks are listed first. + + if (network->IsPrivate()) + continue; + + const bool network_is_policy_managed = + !network->profile_path().empty() && !network->guid().empty() && + managed_configuration_handler_->FindPolicyByGuidAndProfile( + network->guid(), network->profile_path()); + if (network_is_policy_managed) + continue; + + NET_LOG_EVENT("Disconnect Forced by Policy", network->path()); + DBusThreadManager::Get()->GetShillServiceClient()->Disconnect( + dbus::ObjectPath(network->path()), base::Bind(&base::DoNothing), + base::Bind(&network_handler::ShillErrorCallbackFunction, + "AutoConnectHandler.Disconnect failed", network->path(), + network_handler::ErrorCallback())); + } +} + +} // namespace chromeos diff --git a/chromeos/network/auto_connect_handler.h b/chromeos/network/auto_connect_handler.h new file mode 100644 index 0000000000000..3d0eb54ac6e40 --- /dev/null +++ b/chromeos/network/auto_connect_handler.h @@ -0,0 +1,108 @@ +// 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 CHROMEOS_NETWORK_AUTO_CONNECT_HANDLER_H_ +#define CHROMEOS_NETWORK_AUTO_CONNECT_HANDLER_H_ + +#include + +#include "base/macros.h" +#include "chromeos/chromeos_export.h" +#include "chromeos/login/login_state.h" +#include "chromeos/network/client_cert_resolver.h" +#include "chromeos/network/network_connection_handler.h" +#include "chromeos/network/network_handler.h" +#include "chromeos/network/network_policy_observer.h" + +namespace chromeos { + +class CHROMEOS_EXPORT AutoConnectHandler + : public LoginState::Observer, + public NetworkPolicyObserver, + public NetworkConnectionHandler::Observer, + public ClientCertResolver::Observer { + public: + ~AutoConnectHandler() override; + + // LoginState::Observer + void LoggedInStateChanged() override; + + // NetworkConnectionHandler::Observer + void ConnectToNetworkRequested(const std::string& service_path) override; + + // NetworkPolicyObserver + void PoliciesChanged(const std::string& userhash) override; + void PoliciesApplied(const std::string& userhash) override; + + // ClientCertResolver::Observer + void ResolveRequestCompleted(bool network_properties_changed) override; + + private: + friend class NetworkHandler; + friend class AutoConnectHandlerTest; + + AutoConnectHandler(); + + void Init(ClientCertResolver* client_cert_resolver, + NetworkConnectionHandler* network_connection_handler, + NetworkStateHandler* network_state_handler, + ManagedNetworkConfigurationHandler* + managed_network_configuration_handler); + + // If the user logged in already and the policy to prevent unmanaged & shared + // networks to autoconnect is enabled, then disconnects all such networks + // except wired networks. It will do this only once after the user logged in + // and the device policy was available. + // This is enforced once after a user logs in 1) to allow mananged networks to + // autoconnect and 2) to prevent a previous user from foisting a network on + // the new user. Therefore, this function is called at login and when the + // device policy is changed. + void DisconnectIfPolicyRequires(); + + // Disconnects from all unmanaged and shared WiFi networks that are currently + // connected or connecting. + void DisconnectFromUnmanagedSharedWiFiNetworks(); + + // Requests and if possible connects to the 'best' available network, see + // CheckBestConnection(). + void RequestBestConnection(); + + // If a request to connect to the best network is pending and all requirements + // are fulfilled (like policy loaded, certificate patterns being resolved), + // then this will call ConnectToBestWifiNetwork of |network_state_handler_|. + void CheckBestConnection(); + + // Local references to the associated handler instances. + ClientCertResolver* client_cert_resolver_; + NetworkConnectionHandler* network_connection_handler_; + NetworkStateHandler* network_state_handler_; + ManagedNetworkConfigurationHandler* managed_configuration_handler_; + + // Whether a request to connect to the best network is pending. If true, once + // all requirements are met (like policy loaded, certificate patterns being + // resolved), the request is forwarded to the |network_state_handler_|. + bool request_best_connection_pending_; + + // Whether the device policy, which might be empty, is already applied. + bool device_policy_applied_; + + // Whether the user policy of the first user who logged in is already applied. + // The policy might be empty. + bool user_policy_applied_; + + // Whether at least once client certificate patterns were checked and if any + // existed resolved. Even if there are no certificate patterns, this will be + // eventually true. + bool client_certs_resolved_; + + // Whether the autoconnect policy was applied already, see + // DisconnectIfPolicyRequires(). + bool applied_autoconnect_policy_; + + DISALLOW_COPY_AND_ASSIGN(AutoConnectHandler); +}; + +} // namespace chromeos + +#endif // CHROMEOS_NETWORK_AUTO_CONNECT_HANDLER_H_ diff --git a/chromeos/network/auto_connect_handler_unittest.cc b/chromeos/network/auto_connect_handler_unittest.cc new file mode 100644 index 0000000000000..dda7ecc0ca660 --- /dev/null +++ b/chromeos/network/auto_connect_handler_unittest.cc @@ -0,0 +1,475 @@ +// 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 "chromeos/network/auto_connect_handler.h" + +#include + +#include "base/bind.h" +#include "base/callback.h" +#include "base/files/file_util.h" +#include "base/json/json_reader.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/strings/stringprintf.h" +#include "chromeos/cert_loader.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/shill_device_client.h" +#include "chromeos/dbus/shill_manager_client.h" +#include "chromeos/dbus/shill_profile_client.h" +#include "chromeos/dbus/shill_service_client.h" +#include "chromeos/network/client_cert_resolver.h" +#include "chromeos/network/managed_network_configuration_handler_impl.h" +#include "chromeos/network/network_configuration_handler.h" +#include "chromeos/network/network_profile_handler.h" +#include "chromeos/network/network_state_handler.h" +#include "chromeos/network/onc/onc_utils.h" +#include "components/onc/onc_constants.h" +#include "crypto/scoped_nss_types.h" +#include "crypto/scoped_test_nss_db.h" +#include "net/base/net_errors.h" +#include "net/base/test_data_directory.h" +#include "net/cert/nss_cert_database_chromeos.h" +#include "net/cert/x509_certificate.h" +#include "net/test/cert_test_util.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/cros_system_api/dbus/service_constants.h" + +// http://crbug.com/418369 +#ifdef NDEBUG + +namespace chromeos { + +namespace { + +const char* kUserHash = "user_hash"; + +void ConfigureCallback(const dbus::ObjectPath& result) { +} + +void FailErrorCallback(const std::string& error_name, + const std::string& error_message) { + // This function is not expected to be called. + EXPECT_TRUE(false); +} + +class TestCertResolveObserver : public ClientCertResolver::Observer { + public: + explicit TestCertResolveObserver(ClientCertResolver* cert_resolver) + : changed_network_properties_(false), cert_resolver_(cert_resolver) { + cert_resolver_->AddObserver(this); + } + + void ResolveRequestCompleted(bool changed_network_properties) override { + cert_resolver_->RemoveObserver(this); + changed_network_properties_ = changed_network_properties; + } + + bool DidNetworkPropertiesChange() { return changed_network_properties_; } + + private: + bool changed_network_properties_; + ClientCertResolver* cert_resolver_; +}; + +} // namespace + +class AutoConnectHandlerTest : public testing::Test { + public: + AutoConnectHandlerTest() + : test_manager_client_(nullptr), test_service_client_(nullptr) {} + + void SetUp() override { + ASSERT_TRUE(test_nssdb_.is_open()); + + // Use the same DB for public and private slot. + test_nsscertdb_.reset(new net::NSSCertDatabaseChromeOS( + crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_nssdb_.slot())), + crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_nssdb_.slot())))); + test_nsscertdb_->SetSlowTaskRunnerForTest(message_loop_.task_runner()); + + CertLoader::Initialize(); + CertLoader::ForceHardwareBackedForTesting(); + + DBusThreadManager::Initialize(); + DBusThreadManager* dbus_manager = DBusThreadManager::Get(); + test_manager_client_ = + dbus_manager->GetShillManagerClient()->GetTestInterface(); + test_service_client_ = + dbus_manager->GetShillServiceClient()->GetTestInterface(); + + test_manager_client_->AddTechnology(shill::kTypeWifi, true /* enabled */); + dbus_manager->GetShillDeviceClient()->GetTestInterface()->AddDevice( + "/device/wifi1", shill::kTypeWifi, "wifi_device1"); + test_manager_client_->AddTechnology(shill::kTypeCellular, + true /* enabled */); + dbus_manager->GetShillProfileClient()->GetTestInterface()->AddProfile( + "shared_profile_path", std::string() /* shared profile */); + dbus_manager->GetShillProfileClient()->GetTestInterface()->AddProfile( + "user_profile_path", kUserHash); + + base::RunLoop().RunUntilIdle(); + LoginState::Initialize(); + network_state_handler_.reset(NetworkStateHandler::InitializeForTest()); + network_config_handler_.reset( + NetworkConfigurationHandler::InitializeForTest( + network_state_handler_.get())); + + network_profile_handler_.reset(new NetworkProfileHandler()); + network_profile_handler_->Init(); + + managed_config_handler_.reset(new ManagedNetworkConfigurationHandlerImpl()); + managed_config_handler_->Init( + network_state_handler_.get(), network_profile_handler_.get(), + network_config_handler_.get(), nullptr /* network_device_handler */); + + client_cert_resolver_.reset(new ClientCertResolver()); + client_cert_resolver_->Init(network_state_handler_.get(), + managed_config_handler_.get()); + client_cert_resolver_->SetSlowTaskRunnerForTest( + message_loop_.task_runner()); + + auto_connect_handler_.reset(new AutoConnectHandler()); + auto_connect_handler_->Init(client_cert_resolver_.get(), + nullptr, // no connection handler + network_state_handler_.get(), + managed_config_handler_.get()); + + base::RunLoop().RunUntilIdle(); + } + + void TearDown() override { + auto_connect_handler_.reset(); + client_cert_resolver_.reset(); + managed_config_handler_.reset(); + network_profile_handler_.reset(); + network_config_handler_.reset(); + network_state_handler_.reset(); + CertLoader::Shutdown(); + LoginState::Shutdown(); + DBusThreadManager::Shutdown(); + } + + protected: + bool Configure(const std::string& json_string) { + scoped_ptr json_dict = + onc::ReadDictionaryFromJson(json_string); + if (!json_dict) { + LOG(ERROR) << "Error parsing json: " << json_string; + return false; + } + DBusThreadManager::Get()->GetShillManagerClient()->ConfigureService( + *json_dict, base::Bind(&ConfigureCallback), + base::Bind(&FailErrorCallback)); + base::RunLoop().RunUntilIdle(); + return true; + } + + std::string GetServiceState(const std::string& service_path) { + const base::DictionaryValue* properties = + test_service_client_->GetServiceProperties(service_path); + std::string result; + if (properties) + properties->GetStringWithoutPathExpansion(shill::kStateProperty, &result); + return result; + } + + void StartCertLoader() { + CertLoader::Get()->StartWithNSSDB(test_nsscertdb_.get()); + base::RunLoop().RunUntilIdle(); + } + + void LoginToRegularUser() { + LoginState::Get()->SetLoggedInState(LoginState::LOGGED_IN_ACTIVE, + LoginState::LOGGED_IN_USER_REGULAR); + base::RunLoop().RunUntilIdle(); + } + + scoped_refptr ImportTestClientCert() { + net::CertificateList ca_cert_list = net::CreateCertificateListFromFile( + net::GetTestCertsDirectory(), "client_1_ca.pem", + net::X509Certificate::FORMAT_AUTO); + if (ca_cert_list.empty()) { + LOG(ERROR) << "No CA cert loaded."; + return nullptr; + } + net::NSSCertDatabase::ImportCertFailureList failures; + EXPECT_TRUE(test_nsscertdb_->ImportCACerts( + ca_cert_list, net::NSSCertDatabase::TRUST_DEFAULT, &failures)); + if (!failures.empty()) { + LOG(ERROR) << net::ErrorToString(failures[0].net_error); + return nullptr; + } + + // Import a client cert signed by that CA. + scoped_refptr client_cert( + net::ImportClientCertAndKeyFromFile(net::GetTestCertsDirectory(), + "client_1.pem", "client_1.pk8", + test_nssdb_.slot())); + return client_cert; + } + + void SetupPolicy(const std::string& network_configs_json, + const base::DictionaryValue& global_config, + bool user_policy) { + scoped_ptr network_configs(new base::ListValue); + if (!network_configs_json.empty()) { + std::string error; + base::Value* network_configs_value = base::JSONReader::ReadAndReturnError( + network_configs_json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, + &error); + ASSERT_TRUE(network_configs_value) << error; + base::ListValue* network_configs_list = nullptr; + ASSERT_TRUE(network_configs_value->GetAsList(&network_configs_list)); + network_configs.reset(network_configs_list); + } + + if (user_policy) { + managed_config_handler_->SetPolicy(::onc::ONC_SOURCE_USER_POLICY, + kUserHash, *network_configs, + global_config); + } else { + managed_config_handler_->SetPolicy(::onc::ONC_SOURCE_DEVICE_POLICY, + std::string(), // no username hash + *network_configs, global_config); + } + base::RunLoop().RunUntilIdle(); + } + + scoped_ptr auto_connect_handler_; + scoped_ptr client_cert_resolver_; + scoped_ptr network_state_handler_; + scoped_ptr network_config_handler_; + scoped_ptr managed_config_handler_; + scoped_ptr network_profile_handler_; + ShillManagerClient::TestInterface* test_manager_client_; + ShillServiceClient::TestInterface* test_service_client_; + crypto::ScopedTestNSSDB test_nssdb_; + scoped_ptr test_nsscertdb_; + base::MessageLoopForUI message_loop_; + + private: + DISALLOW_COPY_AND_ASSIGN(AutoConnectHandlerTest); +}; + +namespace { + +const char* kConfigUnmanagedSharedConnected = + "{ \"GUID\": \"wifi0\", \"Type\": \"wifi\", \"State\": \"online\", " + " \"Security\": \"wpa\" }"; +const char* kConfigManagedSharedConnectable = + "{ \"GUID\": \"wifi1\", \"Type\": \"wifi\", \"State\": \"idle\", " + " \"Connectable\": true, \"Security\": \"wpa\" }"; + +const char* kPolicy = + "[ { \"GUID\": \"wifi1\"," + " \"Name\": \"wifi1\"," + " \"Type\": \"WiFi\"," + " \"WiFi\": {" + " \"Security\": \"WPA-PSK\"," + " \"SSID\": \"wifi1\"," + " \"Passphrase\": \"passphrase\"" + " }" + "} ]"; + +const char* kPolicyCertPattern = + "[ { \"GUID\": \"wifi1\"," + " \"Name\": \"wifi1\"," + " \"Type\": \"WiFi\"," + " \"WiFi\": {" + " \"Security\": \"WPA-EAP\"," + " \"SSID\": \"wifi1\"," + " \"EAP\": {" + " \"Outer\": \"EAP-TLS\"," + " \"ClientCertType\": \"Pattern\"," + " \"ClientCertPattern\": {" + " \"Issuer\": {" + " \"CommonName\": \"B CA\"" + " }" + " }" + " }" + " }" + "} ]"; +} // namespace + +TEST_F(AutoConnectHandlerTest, ReconnectOnCertLoading) { + EXPECT_TRUE(Configure(kConfigUnmanagedSharedConnected)); + EXPECT_TRUE(Configure(kConfigManagedSharedConnectable)); + test_manager_client_->SetBestServiceToConnect("wifi1"); + + // User login shouldn't trigger any change until the certificates and policy + // are loaded. + LoginToRegularUser(); + EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi0")); + EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi1")); + + // Applying the policy which restricts autoconnect should disconnect from the + // shared, unmanaged network. + base::DictionaryValue global_config; + global_config.SetBooleanWithoutPathExpansion( + ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect, + true); + + SetupPolicy(std::string(), // no network configs + base::DictionaryValue(), // no global config + true); // load as user policy + SetupPolicy(kPolicy, global_config, false /* load as device policy */); + EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi0")); + EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi1")); + + // Certificate loading should trigger connecting to the 'best' network. + StartCertLoader(); + EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi0")); + EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi1")); +} + +TEST_F(AutoConnectHandlerTest, ReconnectOnCertPatternResolved) { + EXPECT_TRUE(Configure(kConfigUnmanagedSharedConnected)); + EXPECT_TRUE(Configure(kConfigManagedSharedConnectable)); + test_manager_client_->SetBestServiceToConnect("wifi0"); + + SetupPolicy(std::string(), // no device policy + base::DictionaryValue(), // no global config + false); // load as device policy + LoginToRegularUser(); + StartCertLoader(); + SetupPolicy(kPolicyCertPattern, + base::DictionaryValue(), // no global config + true); // load as user policy + + EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi0")); + EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi1")); + + test_manager_client_->SetBestServiceToConnect("wifi1"); + TestCertResolveObserver observer(client_cert_resolver_.get()); + + scoped_refptr cert = ImportTestClientCert(); + ASSERT_TRUE(cert.get()); + + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(observer.DidNetworkPropertiesChange()); + + EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi0")); + EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi1")); +} + +// Ensure that resolving of certificate patterns only triggers a reconnect if at +// least one pattern was resolved. +TEST_F(AutoConnectHandlerTest, NoReconnectIfNoCertResolved) { + EXPECT_TRUE(Configure(kConfigUnmanagedSharedConnected)); + EXPECT_TRUE(Configure(kConfigManagedSharedConnectable)); + test_manager_client_->SetBestServiceToConnect("wifi0"); + + SetupPolicy(std::string(), // no device policy + base::DictionaryValue(), // no global config + false); // load as device policy + LoginToRegularUser(); + StartCertLoader(); + SetupPolicy(kPolicy, + base::DictionaryValue(), // no global config + true); // load as user policy + + EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi0")); + EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi1")); + + test_manager_client_->SetBestServiceToConnect("wifi1"); + TestCertResolveObserver observer(client_cert_resolver_.get()); + scoped_refptr cert = ImportTestClientCert(); + ASSERT_TRUE(cert.get()); + + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(observer.DidNetworkPropertiesChange()); + + EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi0")); + EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi1")); +} + +TEST_F(AutoConnectHandlerTest, DisconnectOnPolicyLoading) { + EXPECT_TRUE(Configure(kConfigUnmanagedSharedConnected)); + EXPECT_TRUE(Configure(kConfigManagedSharedConnectable)); + + // User login and certificate loading shouldn't trigger any change until the + // policy is loaded. + LoginToRegularUser(); + StartCertLoader(); + EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi0")); + EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi1")); + + base::DictionaryValue global_config; + global_config.SetBooleanWithoutPathExpansion( + ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect, + true); + + // Applying the policy which restricts autoconnect should disconnect from the + // shared, unmanaged network. + // Because no best service is set, the fake implementation of + // ConnectToBestServices will be a no-op. + SetupPolicy(kPolicy, global_config, false /* load as device policy */); + EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi0")); + EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi1")); +} + +// After login a reconnect is triggered even if there is no managed network. +TEST_F(AutoConnectHandlerTest, ReconnectAfterLogin) { + EXPECT_TRUE(Configure(kConfigUnmanagedSharedConnected)); + EXPECT_TRUE(Configure(kConfigManagedSharedConnectable)); + test_manager_client_->SetBestServiceToConnect("wifi1"); + + // User login and certificate loading shouldn't trigger any change until the + // policy is loaded. + LoginToRegularUser(); + StartCertLoader(); + EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi0")); + EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi1")); + + // Applying an empty device policy will not trigger anything yet, until also + // the user policy is applied. + SetupPolicy(std::string(), // no network configs + base::DictionaryValue(), // no global config + false); // load as device policy + EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi0")); + EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi1")); + + // Applying also an empty user policy should trigger connecting to the 'best' + // network. + SetupPolicy(std::string(), // no network configs + base::DictionaryValue(), // no global config + true); // load as user policy + EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi0")); + EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi1")); +} + +TEST_F(AutoConnectHandlerTest, ManualConnectAbortsReconnectAfterLogin) { + EXPECT_TRUE(Configure(kConfigUnmanagedSharedConnected)); + EXPECT_TRUE(Configure(kConfigManagedSharedConnectable)); + test_manager_client_->SetBestServiceToConnect("wifi1"); + + // User login and certificate loading shouldn't trigger any change until the + // policy is loaded. + LoginToRegularUser(); + StartCertLoader(); + SetupPolicy(std::string(), // no network configs + base::DictionaryValue(), // no global config + false); // load as device policy + + EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi0")); + EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi1")); + + // A manual connect request should prevent a reconnect after login. + auto_connect_handler_->ConnectToNetworkRequested( + std::string() /* service_path */); + + // Applying the user policy after login would usually trigger connecting to + // the 'best' network. But the manual connect prevents this. + SetupPolicy(std::string(), // no network configs + base::DictionaryValue(), // no global config + true); // load as user policy + EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi0")); + EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi1")); +} + +} // namespace chromeos + +#endif diff --git a/chromeos/network/managed_network_configuration_handler_impl.cc b/chromeos/network/managed_network_configuration_handler_impl.cc index 527dd5ab7e18b..ebe5d542193f6 100644 --- a/chromeos/network/managed_network_configuration_handler_impl.cc +++ b/chromeos/network/managed_network_configuration_handler_impl.cc @@ -404,7 +404,8 @@ void ManagedNetworkConfigurationHandlerImpl::SetPolicy( STLDeleteValues(&old_per_network_config); ApplyOrQueuePolicies(userhash, &modified_policies); - FOR_EACH_OBSERVER(NetworkPolicyObserver, observers_, PolicyChanged(userhash)); + FOR_EACH_OBSERVER(NetworkPolicyObserver, observers_, + PoliciesChanged(userhash)); } bool ManagedNetworkConfigurationHandlerImpl::IsAnyPolicyApplicationRunning() diff --git a/chromeos/network/managed_network_configuration_handler_impl.h b/chromeos/network/managed_network_configuration_handler_impl.h index d9a89bd846f2a..433987ce7d556 100644 --- a/chromeos/network/managed_network_configuration_handler_impl.h +++ b/chromeos/network/managed_network_configuration_handler_impl.h @@ -106,6 +106,7 @@ class CHROMEOS_EXPORT ManagedNetworkConfigurationHandlerImpl void OnPoliciesApplied(const NetworkProfile& profile) override; private: + friend class AutoConnectHandlerTest; friend class ClientCertResolverTest; friend class ManagedNetworkConfigurationHandlerTest; friend class NetworkConnectionHandlerTest; diff --git a/chromeos/network/network_connection_handler.cc b/chromeos/network/network_connection_handler.cc index 018d924cef89f..79e4ea2d0758f 100644 --- a/chromeos/network/network_connection_handler.cc +++ b/chromeos/network/network_connection_handler.cc @@ -152,9 +152,7 @@ NetworkConnectionHandler::NetworkConnectionHandler() network_state_handler_(NULL), configuration_handler_(NULL), logged_in_(false), - certificates_loaded_(false), - applied_autoconnect_policy_(false), - requested_connect_to_best_network_(false) { + certificates_loaded_(false) { } NetworkConnectionHandler::~NetworkConnectionHandler() { @@ -191,11 +189,7 @@ void NetworkConnectionHandler::Init( network_state_handler_->AddObserver(this, FROM_HERE); } configuration_handler_ = network_configuration_handler; - - if (managed_network_configuration_handler) { - managed_configuration_handler_ = managed_network_configuration_handler; - managed_configuration_handler_->AddObserver(this); - } + managed_configuration_handler_ = managed_network_configuration_handler; // After this point, the NetworkConnectionHandler is fully initialized (all // handler references set, observers registered, ...). @@ -204,6 +198,14 @@ void NetworkConnectionHandler::Init( LoggedInStateChanged(); } +void NetworkConnectionHandler::AddObserver(Observer* observer) { + observers_.AddObserver(observer); +} + +void NetworkConnectionHandler::RemoveObserver(Observer* observer) { + observers_.RemoveObserver(observer); +} + void NetworkConnectionHandler::LoggedInStateChanged() { LoginState* login_state = LoginState::Get(); if (logged_in_ || !login_state->IsUserLoggedIn()) @@ -212,8 +214,6 @@ void NetworkConnectionHandler::LoggedInStateChanged() { NET_LOG_EVENT("Logged In", ""); logged_in_ = true; logged_in_time_ = base::TimeTicks::Now(); - - DisconnectIfPolicyRequires(); } void NetworkConnectionHandler::OnCertificatesLoaded( @@ -221,20 +221,8 @@ void NetworkConnectionHandler::OnCertificatesLoaded( bool initial_load) { certificates_loaded_ = true; NET_LOG_EVENT("Certificates Loaded", ""); - if (queued_connect_) { + if (queued_connect_) ConnectToQueuedNetwork(); - } else if (initial_load) { - // Connecting to the "best" available network requires certificates to be - // loaded. Try to connect now. - ConnectToBestNetworkAfterLogin(); - } -} - -void NetworkConnectionHandler::PolicyChanged(const std::string& userhash) { - // Ignore user policies. - if (!userhash.empty()) - return; - DisconnectIfPolicyRequires(); } void NetworkConnectionHandler::ConnectToNetwork( @@ -243,6 +231,9 @@ void NetworkConnectionHandler::ConnectToNetwork( const network_handler::ErrorCallback& error_callback, bool check_error_state) { NET_LOG_USER("ConnectToNetwork", service_path); + FOR_EACH_OBSERVER(Observer, observers_, + ConnectToNetworkRequested(service_path)); + // Clear any existing queued connect request. queued_connect_.reset(); if (HasConnectingNetwork(service_path)) { @@ -761,66 +752,4 @@ void NetworkConnectionHandler::HandleShillDisconnectSuccess( success_callback.Run(); } -void NetworkConnectionHandler::ConnectToBestNetworkAfterLogin() { - if (requested_connect_to_best_network_ || !applied_autoconnect_policy_ || - !certificates_loaded_) { - return; - } - - requested_connect_to_best_network_ = true; - network_state_handler_->ConnectToBestWifiNetwork(); -} - -void NetworkConnectionHandler::DisconnectIfPolicyRequires() { - if (applied_autoconnect_policy_ || !LoginState::Get()->IsUserLoggedIn()) - return; - - const base::DictionaryValue* global_network_config = - managed_configuration_handler_->GetGlobalConfigFromPolicy(std::string()); - if (!global_network_config) - return; - - applied_autoconnect_policy_ = true; - - bool only_policy_autoconnect = false; - global_network_config->GetBooleanWithoutPathExpansion( - ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect, - &only_policy_autoconnect); - - if (only_policy_autoconnect) - DisconnectFromUnmanagedSharedWiFiNetworks(); - - ConnectToBestNetworkAfterLogin(); -} - -void NetworkConnectionHandler::DisconnectFromUnmanagedSharedWiFiNetworks() { - NET_LOG_DEBUG("DisconnectFromUnmanagedSharedWiFiNetworks", ""); - - NetworkStateHandler::NetworkStateList networks; - network_state_handler_->GetVisibleNetworkListByType( - NetworkTypePattern::Wireless(), &networks); - for (NetworkStateHandler::NetworkStateList::const_iterator it = - networks.begin(); - it != networks.end(); - ++it) { - const NetworkState* network = *it; - if (!(network->IsConnectingState() || network->IsConnectedState())) - break; // Connected and connecting networks are listed first. - - if (network->IsPrivate()) - continue; - - const bool network_is_policy_managed = - !network->profile_path().empty() && !network->guid().empty() && - managed_configuration_handler_->FindPolicyByGuidAndProfile( - network->guid(), network->profile_path()); - if (network_is_policy_managed) - continue; - - NET_LOG_EVENT("Disconnect Forced by Policy", network->path()); - CallShillDisconnect( - network->path(), base::Closure(), network_handler::ErrorCallback()); - } -} - } // namespace chromeos diff --git a/chromeos/network/network_connection_handler.h b/chromeos/network/network_connection_handler.h index 73ecd669a4b80..bdcf89dda72a0 100644 --- a/chromeos/network/network_connection_handler.h +++ b/chromeos/network/network_connection_handler.h @@ -5,12 +5,14 @@ #ifndef CHROMEOS_NETWORK_NETWORK_CONNECTION_HANDLER_H_ #define CHROMEOS_NETWORK_NETWORK_CONNECTION_HANDLER_H_ +#include #include #include #include "base/basictypes.h" #include "base/callback.h" #include "base/memory/weak_ptr.h" +#include "base/observer_list.h" #include "base/time/time.h" #include "base/values.h" #include "chromeos/cert_loader.h" @@ -19,7 +21,6 @@ #include "chromeos/login/login_state.h" #include "chromeos/network/network_handler.h" #include "chromeos/network/network_handler_callbacks.h" -#include "chromeos/network/network_policy_observer.h" #include "chromeos/network/network_state_handler_observer.h" namespace chromeos { @@ -46,9 +47,21 @@ class CHROMEOS_EXPORT NetworkConnectionHandler : public LoginState::Observer, public CertLoader::Observer, public NetworkStateHandlerObserver, - public NetworkPolicyObserver, public base::SupportsWeakPtr { public: + class Observer { + public: + // Called if a connection to network |service_path| was requested, by + // calling ConnectToNetwork. + virtual void ConnectToNetworkRequested(const std::string& service_path) = 0; + + protected: + virtual ~Observer() {} + + private: + DISALLOW_ASSIGN(Observer); + }; + // Constants for |error_name| from |error_callback| for Connect. // No network matching |service_path| is found (hidden networks must be @@ -93,6 +106,9 @@ class CHROMEOS_EXPORT NetworkConnectionHandler virtual ~NetworkConnectionHandler(); + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + // ConnectToNetwork() will start an asynchronous connection attempt. // On success, |success_callback| will be called. // On failure, |error_callback| will be called with |error_name| one of the @@ -137,9 +153,6 @@ class CHROMEOS_EXPORT NetworkConnectionHandler virtual void OnCertificatesLoaded(const net::CertificateList& cert_list, bool initial_load) override; - // NetworkPolicyObserver - virtual void PolicyChanged(const std::string& userhash) override; - private: friend class NetworkHandler; friend class NetworkConnectionHandlerTest; @@ -206,26 +219,7 @@ class CHROMEOS_EXPORT NetworkConnectionHandler void HandleShillDisconnectSuccess(const std::string& service_path, const base::Closure& success_callback); - // If the policy to prevent unmanaged & shared networks to autoconnect is - // enabled, then disconnect all such networks except wired networks. Does - // nothing on consecutive calls. - // This is enforced once after a user logs in 1) to allow mananged networks to - // autoconnect and 2) to prevent a previous user from foisting a network on - // the new user. Therefore, this function is called on startup, at login and - // when the device policy is changed. - void DisconnectIfPolicyRequires(); - - // Disconnects from all unmanaged and shared WiFi networks that are currently - // connected or connecting. - void DisconnectFromUnmanagedSharedWiFiNetworks(); - - // Requests a connect to the 'best' available network once after login and - // after any disconnect required by policy is executed (see - // DisconnectIfPolicyRequires()). To include networks with client - // certificates, no request is sent until certificates are loaded. Therefore, - // this function is called on the initial certificate load and by - // DisconnectIfPolicyRequires(). - void ConnectToBestNetworkAfterLogin(); + ObserverList observers_; // Local references to the associated handler instances. CertLoader* cert_loader_; @@ -243,14 +237,6 @@ class CHROMEOS_EXPORT NetworkConnectionHandler bool certificates_loaded_; base::TimeTicks logged_in_time_; - // Whether the autoconnect policy was applied already, see - // DisconnectIfPolicyRequires(). - bool applied_autoconnect_policy_; - - // Whether the handler already requested a 'ConnectToBestNetwork' after login, - // see ConnectToBestNetworkAfterLogin(). - bool requested_connect_to_best_network_; - DISALLOW_COPY_AND_ASSIGN(NetworkConnectionHandler); }; diff --git a/chromeos/network/network_connection_handler_unittest.cc b/chromeos/network/network_connection_handler_unittest.cc index b2c61acf8bf94..31b04c2c7ecb6 100644 --- a/chromeos/network/network_connection_handler_unittest.cc +++ b/chromeos/network/network_connection_handler_unittest.cc @@ -426,114 +426,6 @@ TEST_F(NetworkConnectionHandlerTest, EXPECT_EQ(NetworkConnectionHandler::kErrorNotConnected, GetResultAndReset()); } -namespace { - -const char* kConfigUnmanagedSharedConnected = - "{ \"GUID\": \"wifi0\", \"Type\": \"wifi\", \"State\": \"online\", " - " \"Security\": \"wpa\" }"; -const char* kConfigManagedSharedConnectable = - "{ \"GUID\": \"wifi1\", \"Type\": \"wifi\", \"State\": \"idle\", " - " \"Connectable\": true, \"Security\": \"wpa\" }"; - -const char* kPolicy = - "[ { \"GUID\": \"wifi1\"," - " \"Name\": \"wifi1\"," - " \"Type\": \"WiFi\"," - " \"WiFi\": {" - " \"Security\": \"WPA-PSK\"," - " \"SSID\": \"wifi1\"," - " \"Passphrase\": \"passphrase\"" - " }" - "} ]"; - -} // namespace - -TEST_F(NetworkConnectionHandlerTest, ReconnectOnCertLoading) { - EXPECT_TRUE(Configure(kConfigUnmanagedSharedConnected)); - EXPECT_TRUE(Configure(kConfigManagedSharedConnectable)); - test_manager_client_->SetBestServiceToConnect("wifi1"); - - // User login shouldn't trigger any change until the certificates and policy - // are loaded. - LoginToRegularUser(); - EXPECT_EQ(shill::kStateOnline, - GetServiceStringProperty("wifi0", shill::kStateProperty)); - EXPECT_EQ(shill::kStateIdle, - GetServiceStringProperty("wifi1", shill::kStateProperty)); - - // Applying the policy which restricts autoconnect should disconnect from the - // shared, unmanaged network. - base::DictionaryValue global_config; - global_config.SetBooleanWithoutPathExpansion( - ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect, - true); - - SetupPolicy(kPolicy, global_config, false /* load as device policy */); - EXPECT_EQ(shill::kStateIdle, - GetServiceStringProperty("wifi0", shill::kStateProperty)); - EXPECT_EQ(shill::kStateIdle, - GetServiceStringProperty("wifi1", shill::kStateProperty)); - - // Certificate loading should trigger connecting to the 'best' network. - StartCertLoader(); - EXPECT_EQ(shill::kStateIdle, - GetServiceStringProperty("wifi0", shill::kStateProperty)); - EXPECT_EQ(shill::kStateOnline, - GetServiceStringProperty("wifi1", shill::kStateProperty)); -} - -TEST_F(NetworkConnectionHandlerTest, DisconnectOnPolicyLoading) { - EXPECT_TRUE(Configure(kConfigUnmanagedSharedConnected)); - EXPECT_TRUE(Configure(kConfigManagedSharedConnectable)); - - // User login and certificate loading shouldn't trigger any change until the - // policy is loaded. - LoginToRegularUser(); - StartCertLoader(); - EXPECT_EQ(shill::kStateOnline, - GetServiceStringProperty("wifi0", shill::kStateProperty)); - EXPECT_EQ(shill::kStateIdle, - GetServiceStringProperty("wifi1", shill::kStateProperty)); - - base::DictionaryValue global_config; - global_config.SetBooleanWithoutPathExpansion( - ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect, - true); - - // Applying the policy which restricts autoconnect should disconnect from the - // shared, unmanaged network. - // Because no best service is set, the fake implementation of - // ConnectToBestServices will be a no-op. - SetupPolicy(kPolicy, global_config, false /* load as device policy */); - EXPECT_EQ(shill::kStateIdle, - GetServiceStringProperty("wifi0", shill::kStateProperty)); - EXPECT_EQ(shill::kStateIdle, - GetServiceStringProperty("wifi1", shill::kStateProperty)); -} - -TEST_F(NetworkConnectionHandlerTest, ReconnectOnEmptyPolicyLoading) { - EXPECT_TRUE(Configure(kConfigUnmanagedSharedConnected)); - EXPECT_TRUE(Configure(kConfigManagedSharedConnectable)); - test_manager_client_->SetBestServiceToConnect("wifi1"); - - // User login and certificate loading shouldn't trigger any change until the - // policy is loaded. - LoginToRegularUser(); - StartCertLoader(); - EXPECT_EQ(shill::kStateOnline, - GetServiceStringProperty("wifi0", shill::kStateProperty)); - EXPECT_EQ(shill::kStateIdle, - GetServiceStringProperty("wifi1", shill::kStateProperty)); - - // Apply an empty policy should trigger connecting to the 'best' network. - base::DictionaryValue global_config; - SetupPolicy(kPolicy, global_config, false /* load as device policy */); - EXPECT_EQ(shill::kStateIdle, - GetServiceStringProperty("wifi0", shill::kStateProperty)); - EXPECT_EQ(shill::kStateOnline, - GetServiceStringProperty("wifi1", shill::kStateProperty)); -} - } // namespace chromeos #endif diff --git a/chromeos/network/network_handler.cc b/chromeos/network/network_handler.cc index ae2671046c0c3..e54c9351717f6 100644 --- a/chromeos/network/network_handler.cc +++ b/chromeos/network/network_handler.cc @@ -6,6 +6,7 @@ #include "base/threading/worker_pool.h" #include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/network/auto_connect_handler.h" #include "chromeos/network/client_cert_resolver.h" #include "chromeos/network/geolocation_handler.h" #include "chromeos/network/managed_network_configuration_handler_impl.h" @@ -38,6 +39,7 @@ NetworkHandler::NetworkHandler() managed_network_configuration_handler_.reset( new ManagedNetworkConfigurationHandlerImpl()); if (CertLoader::IsInitialized()) { + auto_connect_handler_.reset(new AutoConnectHandler()); network_cert_migrator_.reset(new NetworkCertMigrator()); client_cert_resolver_.reset(new ClientCertResolver()); } @@ -71,6 +73,12 @@ void NetworkHandler::Init() { client_cert_resolver_->Init(network_state_handler_.get(), managed_network_configuration_handler_.get()); } + if (auto_connect_handler_) { + auto_connect_handler_->Init(client_cert_resolver_.get(), + network_connection_handler_.get(), + network_state_handler_.get(), + managed_network_configuration_handler_.get()); + } network_sms_handler_->Init(); geolocation_handler_->Init(); } diff --git a/chromeos/network/network_handler.h b/chromeos/network/network_handler.h index 6949d7040b64a..d5dc403f54f9b 100644 --- a/chromeos/network/network_handler.h +++ b/chromeos/network/network_handler.h @@ -13,6 +13,7 @@ namespace chromeos { +class AutoConnectHandler; class ClientCertResolver; class GeolocationHandler; class ManagedNetworkConfigurationHandler; @@ -79,6 +80,7 @@ class CHROMEOS_EXPORT NetworkHandler { scoped_ptr client_cert_resolver_; scoped_ptr network_activation_handler_; scoped_ptr network_connection_handler_; + scoped_ptr auto_connect_handler_; scoped_ptr network_sms_handler_; scoped_ptr geolocation_handler_; diff --git a/chromeos/network/network_policy_observer.h b/chromeos/network/network_policy_observer.h index c7af61edba503..924a036d31b45 100644 --- a/chromeos/network/network_policy_observer.h +++ b/chromeos/network/network_policy_observer.h @@ -13,10 +13,11 @@ namespace chromeos { class NetworkPolicyObserver { public: - // Called when the policy for |userhash| was set (also when it was updated). - // Note that the policy might not have been applied yet at that time. - // An empty |userhash| designates the device policy. - virtual void PolicyChanged(const std::string& userhash) {} + // Called when the policies for |userhash| were set (also when they were + // updated). An empty |userhash| designates the device policy. + // Note that the policies might be empty and might not have been applied yet + // at that time. + virtual void PoliciesChanged(const std::string& userhash) {} // Called every time a policy application for |userhash| finished. This is // only called once no more policies are pending for |userhash|. diff --git a/chromeos/network/network_profile_handler.h b/chromeos/network/network_profile_handler.h index f3970ad15121f..4d088bdf12a20 100644 --- a/chromeos/network/network_profile_handler.h +++ b/chromeos/network/network_profile_handler.h @@ -61,6 +61,7 @@ class CHROMEOS_EXPORT NetworkProfileHandler static std::string GetSharedProfilePath(); protected: + friend class AutoConnectHandlerTest; friend class ClientCertResolverTest; friend class NetworkConnectionHandlerTest; friend class NetworkHandler; diff --git a/chromeos/settings/timezone_settings.cc b/chromeos/settings/timezone_settings.cc index 1c8f894197704..7403b5ba9dad3 100644 --- a/chromeos/settings/timezone_settings.cc +++ b/chromeos/settings/timezone_settings.cc @@ -88,11 +88,13 @@ static const char* kTimeZones[] = { "Europe/Amsterdam", "Europe/Belgrade", "Europe/Berlin", + "Europe/Bratislava", "Europe/Brussels", "Europe/Budapest", "Europe/Copenhagen", "Europe/Ljubljana", "Europe/Madrid", + "Europe/Malta", "Europe/Oslo", "Europe/Paris", "Europe/Prague", @@ -100,8 +102,10 @@ static const char* kTimeZones[] = { "Europe/Stockholm", "Europe/Sarajevo", "Europe/Tirane", + "Europe/Vaduz", "Europe/Vienna", "Europe/Warsaw", + "Europe/Zagreb", "Europe/Zurich", "Africa/Windhoek", "Africa/Lagos", diff --git a/components/autofill/core/common/password_form.cc b/components/autofill/core/common/password_form.cc index 0f3ee64652340..69c3200334bf2 100644 --- a/components/autofill/core/common/password_form.cc +++ b/components/autofill/core/common/password_form.cc @@ -5,6 +5,7 @@ #include #include "base/strings/string16.h" +#include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "components/autofill/core/common/password_form.h" @@ -73,6 +74,8 @@ std::ostream& operator<<(std::ostream& os, const PasswordForm& form) { << base::UTF16ToUTF8(form.new_password_element) << " new_password_value: " << base::UTF16ToUTF8(form.new_password_value) + << " other_possible_usernames: " + << JoinString(form.other_possible_usernames, '|') << " autocomplete_set:" << form.password_autocomplete_set << " blacklisted: " << form.blacklisted_by_user << " preferred: " << form.preferred diff --git a/components/components_tests.gyp b/components/components_tests.gyp index 76b656a94158a..bfd0b929c466f 100644 --- a/components/components_tests.gyp +++ b/components/components_tests.gyp @@ -284,6 +284,7 @@ # TODO(blundell): Eliminate the need for this dependency in code # that iOS shares. crbug.com/325243 '../content/content_shell_and_tests.gyp:test_support_content', + '../sql/sql.gyp:test_support_sql', '../sync/sync.gyp:sync', '../sync/sync.gyp:test_support_sync_api', '../testing/gmock.gyp:gmock', diff --git a/components/copresence/handlers/directive_handler.cc b/components/copresence/handlers/directive_handler.cc index c2f3b8aefe09d..22138ac33e194 100644 --- a/components/copresence/handlers/directive_handler.cc +++ b/components/copresence/handlers/directive_handler.cc @@ -5,11 +5,18 @@ #include "components/copresence/handlers/directive_handler.h" #include "base/bind.h" +#include "base/guid.h" #include "base/logging.h" #include "base/time/time.h" #include "components/copresence/handlers/audio/audio_directive_handler_impl.h" #include "components/copresence/proto/data.pb.h" +namespace { + +const int kMaxUnlabeledDirectiveTtl = 60000; // 1 minute + +} // namespace + namespace copresence { // Public functions @@ -24,6 +31,7 @@ DirectiveHandler::~DirectiveHandler() {} void DirectiveHandler::Start(WhispernetClient* whispernet_client, const TokensCallback& tokens_cb) { audio_handler_->Initialize(whispernet_client, tokens_cb); + DVLOG(2) << "Directive handler starting"; is_started_ = true; @@ -35,7 +43,10 @@ void DirectiveHandler::Start(WhispernetClient* whispernet_client, pending_directives_.clear(); } -void DirectiveHandler::AddDirective(const Directive& directive) { +void DirectiveHandler::AddDirective(const Directive& original_directive) { + // We may need to modify the directive's TTL. + Directive directive(original_directive); + // We only handle transmit and receive directives. // WiFi and BLE scans aren't implemented. DCHECK_EQ(directive.instruction_type(), TOKEN); @@ -43,9 +54,20 @@ void DirectiveHandler::AddDirective(const Directive& directive) { std::string op_id = directive.published_message_id(); if (op_id.empty()) op_id = directive.subscription_id(); + + // GCM directives will not have a publish or subscribe ID populated. if (op_id.empty()) { - NOTREACHED() << "No operation associated with directive!"; - return; + op_id = base::GenerateGUID(); + DVLOG(3) << "No operation associated with directive. Setting op id to " + << op_id; + + // The app can't cancel these directives, so make sure they're not too long. + if (directive.ttl_millis() > kMaxUnlabeledDirectiveTtl) { + DVLOG(2) << "Cutting TTL of unlabeled directive from " + << directive.ttl_millis() << " down to " + << kMaxUnlabeledDirectiveTtl << " milliseconds"; + directive.set_ttl_millis(kMaxUnlabeledDirectiveTtl); + } } if (!is_started_) { diff --git a/components/copresence/handlers/directive_handler_unittest.cc b/components/copresence/handlers/directive_handler_unittest.cc index 30a0a9672d2af..c388b72f72c98 100644 --- a/components/copresence/handlers/directive_handler_unittest.cc +++ b/components/copresence/handlers/directive_handler_unittest.cc @@ -13,15 +13,25 @@ using testing::ElementsAre; using testing::IsEmpty; +namespace { + +const int64 kMaxUnlabeledTtl = 60000; // 1 minute +const int64 kExcessiveUnlabeledTtl = 120000; // 2 minutes +const int64 kDefaultTtl = 600000; // 10 minutes + +} // namespace + namespace copresence { Directive CreateDirective(const std::string& publish_id, const std::string& subscribe_id, - const std::string& token) { + const std::string& token, + int64 ttl_ms) { Directive directive; directive.set_instruction_type(TOKEN); directive.set_published_message_id(publish_id); directive.set_subscription_id(subscribe_id); + directive.set_ttl_millis(ttl_ms); TokenInstruction* instruction = new TokenInstruction; instruction->set_token_id(token); @@ -31,6 +41,12 @@ Directive CreateDirective(const std::string& publish_id, return directive; } +Directive CreateDirective(const std::string& publish_id, + const std::string& subscribe_id, + const std::string& token) { + return CreateDirective(publish_id, subscribe_id, token, kDefaultTtl); +} + class FakeAudioDirectiveHandler final : public AudioDirectiveHandler { public: FakeAudioDirectiveHandler() {} @@ -40,8 +56,9 @@ class FakeAudioDirectiveHandler final : public AudioDirectiveHandler { void AddInstruction(const TokenInstruction& instruction, const std::string& /* op_id */, - base::TimeDelta /* ttl_ms */) override { + base::TimeDelta ttl) override { added_tokens_.push_back(instruction.token_id()); + added_ttls_.push_back(ttl.InMilliseconds()); } void RemoveInstructions(const std::string& op_id) override { @@ -62,12 +79,17 @@ class FakeAudioDirectiveHandler final : public AudioDirectiveHandler { return added_tokens_; } + const std::vector& added_ttls() const { + return added_ttls_; + } + const std::vector& removed_operations() const { return removed_operations_; } private: std::vector added_tokens_; + std::vector added_ttls_; std::vector removed_operations_; }; @@ -80,11 +102,25 @@ class DirectiveHandlerTest : public testing::Test { make_scoped_ptr(audio_handler_)) {} protected: + void StartDirectiveHandler() { + directive_handler_.Start(whispernet_client_.get(), TokensCallback()); + } + scoped_ptr whispernet_client_; FakeAudioDirectiveHandler* audio_handler_; DirectiveHandler directive_handler_; }; +TEST_F(DirectiveHandlerTest, DirectiveTtl) { + StartDirectiveHandler(); + directive_handler_.AddDirective( + CreateDirective("", "", "token 1", kMaxUnlabeledTtl)); + directive_handler_.AddDirective( + CreateDirective("", "", "token 2", kExcessiveUnlabeledTtl)); + EXPECT_THAT(audio_handler_->added_ttls(), + ElementsAre(kMaxUnlabeledTtl, kMaxUnlabeledTtl)); +} + TEST_F(DirectiveHandlerTest, Queuing) { directive_handler_.AddDirective(CreateDirective("id 1", "", "token 1")); directive_handler_.AddDirective(CreateDirective("", "id 1", "token 2")); @@ -94,10 +130,11 @@ TEST_F(DirectiveHandlerTest, Queuing) { EXPECT_THAT(audio_handler_->added_tokens(), IsEmpty()); EXPECT_THAT(audio_handler_->removed_operations(), IsEmpty()); - directive_handler_.Start(whispernet_client_.get(), TokensCallback()); + StartDirectiveHandler(); directive_handler_.RemoveDirectives("id 3"); EXPECT_THAT(audio_handler_->added_tokens(), ElementsAre("token 3")); + EXPECT_THAT(audio_handler_->added_ttls(), ElementsAre(kDefaultTtl)); EXPECT_THAT(audio_handler_->removed_operations(), ElementsAre("id 3")); } diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.cc index d9d6c5c894642..125d8ac096b62 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.cc @@ -12,7 +12,8 @@ #include "net/url_request/url_request.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_http_job.h" -#include "net/url_request/url_request_job_factory.h" +#include "net/url_request/url_request_job_manager.h" +#include "url/url_constants.h" namespace data_reduction_proxy { @@ -46,9 +47,9 @@ net::URLRequestJob* DataReductionProxyInterceptor::MaybeInterceptResponse( return nullptr; // Returning non-NULL has the effect of restarting the request with the // supplied job. - DCHECK(request->url().SchemeIs("http")); - return request->context()->job_factory()->MaybeCreateJobWithProtocolHandler( - "http", request, network_delegate); + DCHECK(request->url().SchemeIs(url::kHttpScheme)); + return net::URLRequestJobManager::GetInstance()->CreateJob( + request, network_delegate); } } // namespace data_reduction_proxy diff --git a/components/enhanced_bookmarks/enhanced_bookmark_model.cc b/components/enhanced_bookmarks/enhanced_bookmark_model.cc index ffcc02aa0ce2d..e9b8baea3c910 100644 --- a/components/enhanced_bookmarks/enhanced_bookmark_model.cc +++ b/components/enhanced_bookmarks/enhanced_bookmark_model.cc @@ -313,10 +313,7 @@ void EnhancedBookmarkModel::BookmarkNodeRemoved( int old_index, const BookmarkNode* node, const std::set& removed_urls) { - std::string remote_id = GetRemoteId(node); - id_map_.erase(remote_id); - nodes_to_reset_.erase(node); - set_needs_offline_processing_tasks_.erase(node); + RemoveNodeFromMaps(node); FOR_EACH_OBSERVER( EnhancedBookmarkModelObserver, observers_, EnhancedBookmarkRemoved(node)); } @@ -386,6 +383,16 @@ void EnhancedBookmarkModel::AddToIdMap(const BookmarkNode* node) { } } +void EnhancedBookmarkModel::RemoveNodeFromMaps(const BookmarkNode* node) { + for (int i = 0; i < node->child_count(); i++) { + RemoveNodeFromMaps(node->GetChild(i)); + } + std::string remote_id = GetRemoteId(node); + id_map_.erase(remote_id); + nodes_to_reset_.erase(node); + set_needs_offline_processing_tasks_.erase(node); +} + void EnhancedBookmarkModel::ScheduleResetDuplicateRemoteIds() { if (!nodes_to_reset_.empty()) { base::MessageLoopProxy::current()->PostTask( diff --git a/components/enhanced_bookmarks/enhanced_bookmark_model.h b/components/enhanced_bookmarks/enhanced_bookmark_model.h index 4196f647340c0..8bfc566efb062 100644 --- a/components/enhanced_bookmarks/enhanced_bookmark_model.h +++ b/components/enhanced_bookmarks/enhanced_bookmark_model.h @@ -165,6 +165,9 @@ class EnhancedBookmarkModel : public KeyedService, // by a (Schedule)ResetDuplicateRemoteIds call when done adding nodes. void AddToIdMap(const BookmarkNode* node); + // Recursively removes a node and all its children from the various maps. + void RemoveNodeFromMaps(const BookmarkNode* node); + // If there are nodes that needs to reset their remote ids, schedules // ResetDuplicateRemoteIds to be run asynchronously. void ScheduleResetDuplicateRemoteIds(); diff --git a/components/enhanced_bookmarks/enhanced_bookmark_model_unittest.cc b/components/enhanced_bookmarks/enhanced_bookmark_model_unittest.cc index 0d12de17f0f5d..90855bb177840 100644 --- a/components/enhanced_bookmarks/enhanced_bookmark_model_unittest.cc +++ b/components/enhanced_bookmarks/enhanced_bookmark_model_unittest.cc @@ -752,3 +752,15 @@ TEST_F(EnhancedBookmarkModelTest, bookmark_model_->Remove(node->parent(), node->parent()->GetIndexOf(node)); base::RunLoop().RunUntilIdle(); } + +TEST_F(EnhancedBookmarkModelTest, + RemoveParentShouldRemoveChildrenFromMaps) { + const BookmarkNode* parent = AddFolder(); + const BookmarkNode* node = AddBookmark("Title", parent); + std::string remote_id = GetId(node); + EXPECT_EQ(node, model_->BookmarkForRemoteId(remote_id)); + + const BookmarkNode* gp = parent->parent(); + bookmark_model_->Remove(gp, gp->GetIndexOf(parent)); + EXPECT_FALSE(model_->BookmarkForRemoteId(remote_id)); +} diff --git a/components/gcm_driver/gcm_driver_desktop.cc b/components/gcm_driver/gcm_driver_desktop.cc index 352007a58fa94..b2ab93ae35522 100644 --- a/components/gcm_driver/gcm_driver_desktop.cc +++ b/components/gcm_driver/gcm_driver_desktop.cc @@ -650,6 +650,8 @@ base::Time GCMDriverDesktop::GetLastTokenFetchTime() { void GCMDriverDesktop::SetLastTokenFetchTime(const base::Time& time) { DCHECK(ui_thread_->RunsTasksOnCurrentThread()); + last_token_fetch_time_ = time; + io_thread_->PostTask( FROM_HERE, base::Bind(&GCMDriverDesktop::IOWorker::SetLastTokenFetchTime, diff --git a/components/gcm_driver/gcm_driver_desktop_unittest.cc b/components/gcm_driver/gcm_driver_desktop_unittest.cc index e02f8b3789557..f27d0188f6018 100644 --- a/components/gcm_driver/gcm_driver_desktop_unittest.cc +++ b/components/gcm_driver/gcm_driver_desktop_unittest.cc @@ -991,6 +991,13 @@ TEST_F(GCMDriverFunctionalTest, MessagesDeleted) { EXPECT_EQ(kTestAppID1, gcm_app_handler()->app_id()); } +TEST_F(GCMDriverFunctionalTest, LastTokenFetchTime) { + EXPECT_EQ(base::Time(), driver()->GetLastTokenFetchTime()); + base::Time fetch_time = base::Time::Now(); + driver()->SetLastTokenFetchTime(fetch_time); + EXPECT_EQ(fetch_time, driver()->GetLastTokenFetchTime()); +} + // Tests a single instance of GCMDriver. class GCMChannelStatusSyncerTest : public GCMDriverTest { public: diff --git a/components/metrics/metrics_service.cc b/components/metrics/metrics_service.cc index 4fa2e751b91e9..adb8f2cd7cc11 100644 --- a/components/metrics/metrics_service.cc +++ b/components/metrics/metrics_service.cc @@ -549,6 +549,19 @@ void MetricsService::RecordBreakpadHasDebugger(bool has_debugger) { IncrementPrefValue(prefs::kStabilityDebuggerPresent); } +void MetricsService::ClearSavedStabilityMetrics() { + for (size_t i = 0; i < metrics_providers_.size(); ++i) + metrics_providers_[i]->ClearSavedStabilityMetrics(); + + // Reset the prefs that are managed by MetricsService/MetricsLog directly. + local_state_->SetInteger(prefs::kStabilityCrashCount, 0); + local_state_->SetInteger(prefs::kStabilityExecutionPhase, + UNINITIALIZED_PHASE); + local_state_->SetInteger(prefs::kStabilityIncompleteSessionEndCount, 0); + local_state_->SetInteger(prefs::kStabilityLaunchCount, 0); + local_state_->SetBoolean(prefs::kStabilitySessionEndCompleted, true); +} + //------------------------------------------------------------------------------ // private methods //------------------------------------------------------------------------------ @@ -600,18 +613,8 @@ void MetricsService::InitializeMetricsState() { // number of different edge cases, such as if the last version crashed before // it could save off a system profile or if UMA reporting is disabled (which // normally results in stats being accumulated). - if (!has_initial_stability_log_ && version_changed) { - for (size_t i = 0; i < metrics_providers_.size(); ++i) - metrics_providers_[i]->ClearSavedStabilityMetrics(); - - // Reset the prefs that are managed by MetricsService/MetricsLog directly. - local_state_->SetInteger(prefs::kStabilityCrashCount, 0); - local_state_->SetInteger(prefs::kStabilityExecutionPhase, - UNINITIALIZED_PHASE); - local_state_->SetInteger(prefs::kStabilityIncompleteSessionEndCount, 0); - local_state_->SetInteger(prefs::kStabilityLaunchCount, 0); - local_state_->SetBoolean(prefs::kStabilitySessionEndCompleted, true); - } + if (!has_initial_stability_log_ && version_changed) + ClearSavedStabilityMetrics(); // Update session ID. ++session_id_; diff --git a/components/metrics/metrics_service.h b/components/metrics/metrics_service.h index 19794ea47a1d4..db1fae2d7c89c 100644 --- a/components/metrics/metrics_service.h +++ b/components/metrics/metrics_service.h @@ -239,6 +239,9 @@ class MetricsService : public base::HistogramFlattener { void CheckForClonedInstall( scoped_refptr task_runner); + // Clears the stability metrics that are saved in local state. + void ClearSavedStabilityMetrics(); + protected: // Exposed for testing. MetricsLogManager* log_manager() { return &log_manager_; } diff --git a/components/omnibox/omnibox_field_trial.cc b/components/omnibox/omnibox_field_trial.cc index 7ad29563fa163..0955eea6cab90 100644 --- a/components/omnibox/omnibox_field_trial.cc +++ b/components/omnibox/omnibox_field_trial.cc @@ -114,26 +114,14 @@ void OmniboxFieldTrial::ActivateDynamicTrials() { } int OmniboxFieldTrial::GetDisabledProviderTypes() { - // Make sure that Autocomplete dynamic field trials are activated. It's OK to - // call this method multiple times. - ActivateDynamicTrials(); - - // Look for group names in form of "DisabledProviders_" where "mask" - // is a bitmap of disabled provider types (AutocompleteProvider::Type). - int provider_types = 0; - for (int i = 0; i < kMaxAutocompleteDynamicFieldTrials; ++i) { - std::string group_name = base::FieldTrialList::FindFullName( - DynamicFieldTrialName(i)); - const char kDisabledProviders[] = "DisabledProviders_"; - if (!StartsWithASCII(group_name, kDisabledProviders, true)) - continue; - int types = 0; - if (!base::StringToInt(base::StringPiece( - group_name.substr(strlen(kDisabledProviders))), &types)) - continue; - provider_types |= types; + const std::string& types_string = variations::GetVariationParamValue( + kBundledExperimentFieldTrialName, + kDisableProvidersRule); + int types = 0; + if (types_string.empty() || !base::StringToInt(types_string, &types)) { + return 0; } - return provider_types; + return types; } void OmniboxFieldTrial::GetActiveSuggestFieldTrialHashes( @@ -367,6 +355,7 @@ void OmniboxFieldTrial::GetSuggestPollingStrategy(bool* from_last_keystroke, const char OmniboxFieldTrial::kBundledExperimentFieldTrialName[] = "OmniboxBundledExperimentV1"; +const char OmniboxFieldTrial::kDisableProvidersRule[] = "DisableProviders"; const char OmniboxFieldTrial::kShortcutsScoringMaxRelevanceRule[] = "ShortcutsScoringMaxRelevance"; const char OmniboxFieldTrial::kSearchHistoryRule[] = "SearchHistory"; diff --git a/components/omnibox/omnibox_field_trial.h b/components/omnibox/omnibox_field_trial.h index d54b2b31a1795..5a8909d172489 100644 --- a/components/omnibox/omnibox_field_trial.h +++ b/components/omnibox/omnibox_field_trial.h @@ -98,12 +98,11 @@ class OmniboxFieldTrial { // This method may be called multiple times. static void ActivateDynamicTrials(); + // --------------------------------------------------------- + // For any experiment that's part of the bundled omnibox field trial. + // Returns a bitmap containing AutocompleteProvider::Type values // that should be disabled in AutocompleteController. - // This method simply goes over all autocomplete dynamic field trial groups - // and looks for group names like "ProvidersDisabled_NNN" where NNN is - // an integer corresponding to a bitmap mask. All extracted bitmaps - // are OR-ed together and returned as the final result. static int GetDisabledProviderTypes(); // Returns whether the user is in any dynamic field trial where the @@ -300,6 +299,7 @@ class OmniboxFieldTrial { // Exposed publicly for the sake of unittests. static const char kBundledExperimentFieldTrialName[]; // Rule names used by the bundled experiment. + static const char kDisableProvidersRule[]; static const char kShortcutsScoringMaxRelevanceRule[]; static const char kSearchHistoryRule[]; static const char kDemoteByTypeRule[]; diff --git a/components/omnibox/omnibox_field_trial_unittest.cc b/components/omnibox/omnibox_field_trial_unittest.cc index 47f7467462330..fe302714d761d 100644 --- a/components/omnibox/omnibox_field_trial_unittest.cc +++ b/components/omnibox/omnibox_field_trial_unittest.cc @@ -138,32 +138,56 @@ TEST_F(OmniboxFieldTrialTest, GetDisabledProviderTypes) { EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes()); { - SCOPED_TRACE("Invalid groups"); - CreateTestTrial("AutocompleteDynamicTrial_0", "DisabledProviders_"); + SCOPED_TRACE("Outside the bundled field trial."); + CreateTestTrial("AutocompleteDynamicTrial_0", "DisabledProviders_123"); EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes()); + } + + { + SCOPED_TRACE("Valid field trial, missing param."); ResetFieldTrialList(); - CreateTestTrial("AutocompleteDynamicTrial_1", "DisabledProviders_XXX"); + std::map params; + ASSERT_TRUE(variations::AssociateVariationParams( + OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params)); + base::FieldTrialList::CreateFieldTrial( + OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A"); EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes()); + } + + { + SCOPED_TRACE("Valid field trial, empty param value."); ResetFieldTrialList(); - CreateTestTrial("AutocompleteDynamicTrial_1", "DisabledProviders_12abc"); + std::map params; + params[std::string(OmniboxFieldTrial::kDisableProvidersRule)] = ""; + ASSERT_TRUE(variations::AssociateVariationParams( + OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params)); + base::FieldTrialList::CreateFieldTrial( + OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A"); EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes()); } { - SCOPED_TRACE("Valid group name, unsupported trial name."); + SCOPED_TRACE("Valid field trial, invalid param value."); ResetFieldTrialList(); - CreateTestTrial("UnsupportedTrialName", "DisabledProviders_20"); + std::map params; + params[std::string(OmniboxFieldTrial::kDisableProvidersRule)] = "aaa"; + ASSERT_TRUE(variations::AssociateVariationParams( + OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params)); + base::FieldTrialList::CreateFieldTrial( + OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A"); EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes()); } { - SCOPED_TRACE("Valid field and group name."); + SCOPED_TRACE("Valid field trial and param."); ResetFieldTrialList(); - CreateTestTrial("AutocompleteDynamicTrial_2", "DisabledProviders_3"); - EXPECT_EQ(3, OmniboxFieldTrial::GetDisabledProviderTypes()); - // Two groups should be OR-ed together. - CreateTestTrial("AutocompleteDynamicTrial_3", "DisabledProviders_6"); - EXPECT_EQ(7, OmniboxFieldTrial::GetDisabledProviderTypes()); + std::map params; + params[std::string(OmniboxFieldTrial::kDisableProvidersRule)] = "12321"; + ASSERT_TRUE(variations::AssociateVariationParams( + OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params)); + base::FieldTrialList::CreateFieldTrial( + OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A"); + EXPECT_EQ(12321, OmniboxFieldTrial::GetDisabledProviderTypes()); } } diff --git a/components/ownership/owner_settings_service.h b/components/ownership/owner_settings_service.h index a1d7c52308a5a..9be4a0a55dc03 100644 --- a/components/ownership/owner_settings_service.h +++ b/components/ownership/owner_settings_service.h @@ -41,8 +41,8 @@ class OWNERSHIP_EXPORT OwnerSettingsService : public KeyedService { // policy storage.. virtual void OnSignedPolicyStored(bool success) {} - // Called when tentative changes were made to policy, but the policy still - // not signed and stored. + // Called when tentative changes were made to policy, but the + // policy is not signed and stored yet. // // TODO (ygorshenin@, crbug.com/230018): get rid of the method // since it creates DeviceSettingsService's dependency on diff --git a/components/password_manager/core/browser/login_database.cc b/components/password_manager/core/browser/login_database.cc index e1cf8a2f92890..60fa6fdb1f998 100644 --- a/components/password_manager/core/browser/login_database.cc +++ b/components/password_manager/core/browser/login_database.cc @@ -27,7 +27,7 @@ using autofill::PasswordForm; namespace password_manager { -static const int kCurrentVersionNumber = 8; +static const int kCurrentVersionNumber = 9; static const int kCompatibleVersionNumber = 1; Pickle SerializeVector(const std::vector& vec) { @@ -91,7 +91,7 @@ void BindAddStatement(const PasswordForm& form, s->BindString(COLUMN_SIGNON_REALM, form.signon_realm); s->BindInt(COLUMN_SSL_VALID, form.ssl_valid); s->BindInt(COLUMN_PREFERRED, form.preferred); - s->BindInt64(COLUMN_DATE_CREATED, form.date_created.ToTimeT()); + s->BindInt64(COLUMN_DATE_CREATED, form.date_created.ToInternalValue()); s->BindInt(COLUMN_BLACKLISTED_BY_USER, form.blacklisted_by_user); s->BindInt(COLUMN_SCHEME, form.scheme); s->BindInt(COLUMN_PASSWORD_TYPE, form.type); @@ -257,6 +257,19 @@ bool LoginDatabase::MigrateOldVersionsAsNeeded() { // Fall through. // TODO(gcasto): Remove use_additional_auth by copying table. // https://www.sqlite.org/lang_altertable.html + case 8: { + sql::Statement s; + s.Assign(db_.GetCachedStatement(SQL_FROM_HERE, + "UPDATE logins SET " + "date_created = " + "(date_created * ?) + ?")); + s.BindInt64(0, base::Time::kMicrosecondsPerSecond); + s.BindInt64(1, base::Time::kTimeTToMicrosecondsOffset); + if (!s.Run()) + return false; + meta_table_.SetVersionNumber(9); + // Fall through. + } case kCurrentVersionNumber: // Already up to date return true; @@ -311,8 +324,9 @@ void LoginDatabase::ReportMetrics(const std::string& sync_username, bool custom_passphrase_sync_enabled) { sql::Statement s(db_.GetCachedStatement( SQL_FROM_HERE, - "SELECT signon_realm, blacklisted_by_user, COUNT(username_value) " - "FROM logins GROUP BY signon_realm, blacklisted_by_user")); + "SELECT signon_realm, password_type, blacklisted_by_user," + "COUNT(username_value) FROM logins GROUP BY " + "signon_realm, password_type, blacklisted_by_user")); if (!s.is_valid()) return; @@ -322,23 +336,38 @@ void LoginDatabase::ReportMetrics(const std::string& sync_username, custom_passphrase = "WithCustomPassphrase"; } - int total_accounts = 0; + int total_user_created_accounts = 0; + int total_generated_accounts = 0; int blacklisted_sites = 0; while (s.Step()) { - int blacklisted = s.ColumnInt(1); - int accounts_per_site = s.ColumnInt(2); + PasswordForm::Type password_type = + static_cast(s.ColumnInt(1)); + int blacklisted = s.ColumnInt(2); + int accounts_per_site = s.ColumnInt(3); if (blacklisted) { ++blacklisted_sites; + } else if (password_type == PasswordForm::TYPE_GENERATED) { + total_generated_accounts += accounts_per_site; + LogAccountStat( + base::StringPrintf("PasswordManager.AccountsPerSite.AutoGenerated.%s", + custom_passphrase.c_str()), + accounts_per_site); } else { - total_accounts += accounts_per_site; - LogAccountStat(base::StringPrintf("PasswordManager.AccountsPerSite.%s", - custom_passphrase.c_str()), - accounts_per_site); + total_user_created_accounts += accounts_per_site; + LogAccountStat( + base::StringPrintf("PasswordManager.AccountsPerSite.UserCreated.%s", + custom_passphrase.c_str()), + accounts_per_site); } } - LogAccountStat(base::StringPrintf("PasswordManager.TotalAccounts.%s", - custom_passphrase.c_str()), - total_accounts); + LogAccountStat( + base::StringPrintf("PasswordManager.TotalAccounts.UserCreated.%s", + custom_passphrase.c_str()), + total_user_created_accounts); + LogAccountStat( + base::StringPrintf("PasswordManager.TotalAccounts.AutoGenerated.%s", + custom_passphrase.c_str()), + total_generated_accounts); LogAccountStat(base::StringPrintf("PasswordManager.BlacklistedSites.%s", custom_passphrase.c_str()), blacklisted_sites); @@ -355,13 +384,13 @@ void LoginDatabase::ReportMetrics(const std::string& sync_username, usage_statement.ColumnInt(0)); if (type == PasswordForm::TYPE_GENERATED) { - LogTimesUsedStat( - base::StringPrintf("PasswordManager.TimesGeneratedPasswordUsed.%s", - custom_passphrase.c_str()), - usage_statement.ColumnInt(1)); + LogTimesUsedStat(base::StringPrintf( + "PasswordManager.TimesPasswordUsed.AutoGenerated.%s", + custom_passphrase.c_str()), + usage_statement.ColumnInt(1)); } else { LogTimesUsedStat( - base::StringPrintf("PasswordManager.TimesPasswordUsed.%s", + base::StringPrintf("PasswordManager.TimesPasswordUsed.UserCreated.%s", custom_passphrase.c_str()), usage_statement.ColumnInt(1)); } @@ -476,7 +505,7 @@ PasswordStoreChangeList LoginDatabase::UpdateLogin(const PasswordForm& form) { s.BindInt(5, form.times_used); s.BindString16(6, form.submit_element); s.BindInt64(7, form.date_synced.ToInternalValue()); - s.BindInt64(8, form.date_created.ToTimeT()); + s.BindInt64(8, form.date_created.ToInternalValue()); s.BindInt(9, form.blacklisted_by_user); s.BindInt(10, form.scheme); s.BindInt(11, form.type); @@ -527,9 +556,9 @@ bool LoginDatabase::RemoveLoginsCreatedBetween(base::Time delete_begin, sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE, "DELETE FROM logins WHERE " "date_created >= ? AND date_created < ?")); - s.BindInt64(0, delete_begin.ToTimeT()); + s.BindInt64(0, delete_begin.ToInternalValue()); s.BindInt64(1, delete_end.is_null() ? std::numeric_limits::max() - : delete_end.ToTimeT()); + : delete_end.ToInternalValue()); return s.Run(); } @@ -571,8 +600,8 @@ LoginDatabase::EncryptionResult LoginDatabase::InitPasswordFormFromStatement( form->signon_realm = tmp; form->ssl_valid = (s.ColumnInt(COLUMN_SSL_VALID) > 0); form->preferred = (s.ColumnInt(COLUMN_PREFERRED) > 0); - form->date_created = base::Time::FromTimeT( - s.ColumnInt64(COLUMN_DATE_CREATED)); + form->date_created = + base::Time::FromInternalValue(s.ColumnInt64(COLUMN_DATE_CREATED)); form->blacklisted_by_user = (s.ColumnInt(COLUMN_BLACKLISTED_BY_USER) > 0); int scheme_int = s.ColumnInt(COLUMN_SCHEME); DCHECK((scheme_int >= 0) && (scheme_int <= PasswordForm::SCHEME_OTHER)); @@ -711,9 +740,9 @@ bool LoginDatabase::GetLoginsCreatedBetween( "federation_url, is_zero_click FROM logins " "WHERE date_created >= ? AND date_created < ?" "ORDER BY origin_url")); - s.BindInt64(0, begin.ToTimeT()); + s.BindInt64(0, begin.ToInternalValue()); s.BindInt64(1, end.is_null() ? std::numeric_limits::max() - : end.ToTimeT()); + : end.ToInternalValue()); while (s.Step()) { scoped_ptr new_form(new PasswordForm()); diff --git a/components/password_manager/core/browser/login_database_unittest.cc b/components/password_manager/core/browser/login_database_unittest.cc index d738ab495705f..5ec0e2ed88c33 100644 --- a/components/password_manager/core/browser/login_database_unittest.cc +++ b/components/password_manager/core/browser/login_database_unittest.cc @@ -8,11 +8,16 @@ #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/memory/scoped_vector.h" +#include "base/path_service.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/histogram_tester.h" #include "base/time/time.h" #include "components/autofill/core/common/password_form.h" #include "components/password_manager/core/browser/psl_matching_helper.h" +#include "sql/connection.h" +#include "sql/statement.h" +#include "sql/test/test_helpers.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -927,8 +932,6 @@ TEST_F(LoginDatabaseTest, UpdateLogin) { form.submit_element = ASCIIToUTF16("submit_element"); form.date_synced = base::Time::Now(); form.date_created = base::Time::Now() - base::TimeDelta::FromDays(1); - // Remove this line after crbug/374132 is fixed. - form.date_created = base::Time::FromTimeT(form.date_created.ToTimeT()); form.blacklisted_by_user = true; form.scheme = PasswordForm::SCHEME_BASIC; form.type = PasswordForm::TYPE_GENERATED; @@ -949,6 +952,79 @@ TEST_F(LoginDatabaseTest, UpdateLogin) { EXPECT_EQ(form, *result[0]); } +TEST_F(LoginDatabaseTest, ReportMetricsTest) { + PasswordForm password_form; + password_form.origin = GURL("http://example.com"); + password_form.username_value = ASCIIToUTF16("test1@gmail.com"); + password_form.password_value = ASCIIToUTF16("test"); + password_form.signon_realm = "http://example.com/"; + password_form.times_used = 0; + EXPECT_EQ(AddChangeForForm(password_form), db_.AddLogin(password_form)); + + password_form.username_value = ASCIIToUTF16("test2@gmail.com"); + password_form.times_used = 1; + EXPECT_EQ(AddChangeForForm(password_form), db_.AddLogin(password_form)); + + password_form.origin = GURL("http://second.example.com"); + password_form.signon_realm = "http://second.example.com"; + password_form.times_used = 3; + EXPECT_EQ(AddChangeForForm(password_form), db_.AddLogin(password_form)); + + password_form.username_value = ASCIIToUTF16("test3@gmail.com"); + password_form.type = PasswordForm::TYPE_GENERATED; + password_form.times_used = 2; + EXPECT_EQ(AddChangeForForm(password_form), db_.AddLogin(password_form)); + + password_form.origin = GURL("http://third.example.com/"); + password_form.signon_realm = "http://third.example.com/"; + password_form.times_used = 4; + EXPECT_EQ(AddChangeForForm(password_form), db_.AddLogin(password_form)); + + base::HistogramTester histogram_tester; + db_.ReportMetrics("", false); + + histogram_tester.ExpectUniqueSample( + "PasswordManager.TotalAccounts.UserCreated.WithoutCustomPassphrase", + 3, + 1); + histogram_tester.ExpectBucketCount( + "PasswordManager.AccountsPerSite.UserCreated.WithoutCustomPassphrase", + 1, + 1); + histogram_tester.ExpectBucketCount( + "PasswordManager.AccountsPerSite.UserCreated.WithoutCustomPassphrase", + 2, + 1); + histogram_tester.ExpectBucketCount( + "PasswordManager.TimesPasswordUsed.UserCreated.WithoutCustomPassphrase", + 0, + 1); + histogram_tester.ExpectBucketCount( + "PasswordManager.TimesPasswordUsed.UserCreated.WithoutCustomPassphrase", + 1, + 1); + histogram_tester.ExpectBucketCount( + "PasswordManager.TimesPasswordUsed.UserCreated.WithoutCustomPassphrase", + 3, + 1); + histogram_tester.ExpectUniqueSample( + "PasswordManager.TotalAccounts.AutoGenerated.WithoutCustomPassphrase", + 2, + 1); + histogram_tester.ExpectUniqueSample( + "PasswordManager.AccountsPerSite.AutoGenerated.WithoutCustomPassphrase", + 1, + 2); + histogram_tester.ExpectBucketCount( + "PasswordManager.TimesPasswordUsed.AutoGenerated.WithoutCustomPassphrase", + 2, + 1); + histogram_tester.ExpectBucketCount( + "PasswordManager.TimesPasswordUsed.AutoGenerated.WithoutCustomPassphrase", + 4, + 1); +} + #if defined(OS_POSIX) // Only the current user has permission to read the database. // @@ -962,4 +1038,82 @@ TEST_F(LoginDatabaseTest, FilePermissions) { } #endif // defined(OS_POSIX) +class LoginDatabaseMigrationTest : public testing::Test { + protected: + void SetUp() override { + PathService::Get(base::DIR_SOURCE_ROOT, &database_dump_); + database_dump_ = database_dump_.AppendASCII("components") + .AppendASCII("test") + .AppendASCII("data") + .AppendASCII("password_manager") + .AppendASCII("login_db_v8.sql"); + + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + database_path_ = temp_dir_.path().AppendASCII("test.db"); + ASSERT_TRUE( + sql::test::CreateDatabaseFromSQL(database_path_, database_dump_)); + } + + void TearDown() override { + if (!database_path_.empty()) + base::DeleteFile(database_path_, false); + } + + // Returns an empty vector on failure. Otherwise returns the values of the + // date_created field from the logins table. The order of the returned rows + // is well-defined. + std::vector GetDateCreated(const base::FilePath& db_path) { + sql::Connection db; + std::vector results; + if (!db.Open(db_path)) + return results; + + sql::Statement s(db.GetCachedStatement( + SQL_FROM_HERE, + "SELECT date_created from logins order by username_value")); + if (!s.is_valid()) { + db.Close(); + return results; + } + + while (s.Step()) + results.push_back(s.ColumnInt64(0)); + + s.Clear(); + db.Close(); + return results; + } + + base::FilePath database_path_; + + private: + base::FilePath database_dump_; + base::ScopedTempDir temp_dir_; +}; + +// Tests the migration of the login database from version 8 to version 9. +TEST_F(LoginDatabaseMigrationTest, MigrationV8ToV9) { + // Original date, in seconds since UTC epoch. + std::vector date_created(GetDateCreated(database_path_)); + ASSERT_EQ(1402955745, date_created[0]); + ASSERT_EQ(1402950000, date_created[1]); + + // Assert that the database was successfully opened and migrated. + { + LoginDatabase db; + ASSERT_TRUE(db.Init(database_path_)); + } + + // New date, in microseconds since platform independent epoch. + std::vector new_date_created(GetDateCreated(database_path_)); + ASSERT_EQ(13047429345000000, new_date_created[0]); + ASSERT_EQ(13047423600000000, new_date_created[1]); + + // Check that the two dates match up. + for (size_t i = 0; i < date_created.size(); ++i) { + EXPECT_EQ(base::Time::FromInternalValue(new_date_created[i]), + base::Time::FromTimeT(date_created[i])); + } +} + } // namespace password_manager diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc index 4dd75b5fb2550..b4c2e22830ed5 100644 --- a/components/password_manager/core/browser/password_form_manager.cc +++ b/components/password_manager/core/browser/password_form_manager.cc @@ -257,6 +257,17 @@ void PasswordFormManager::ProvisionallySave( is_new_login_ = true; user_action_ = password_changed ? kUserActionChoosePslMatch : kUserActionOverridePassword; + + // Update credential to reflect that it has been used for submission. + // If this isn't updated, then password generation uploads are off for + // sites where PSL matching is required to fill the login form, as two + // PASSWORD votes are uploaded per saved password instead of one. + // + // TODO(gcasto): It would be nice if other state were shared such that if + // say a password was updated on one match it would update on all related + // passwords. This is a much larger change. + UpdateMetadataForUsage(pending_credentials_); + // Normally, the copy of the PSL matched credentials, adapted for the // current domain, is saved automatically without asking the user, because // the copy likely represents the same account, i.e., the one for which @@ -543,9 +554,15 @@ void PasswordFormManager::SaveAsNewLogin(bool reset_preferred_login) { // Upload credentials the first time they are saved. This data is used // by password generation to help determine account creation sites. // Blacklisted credentials will never be used, so don't upload a vote for - // them. - if (!pending_credentials_.blacklisted_by_user) - UploadPasswordForm(pending_credentials_.form_data, autofill::PASSWORD); + // them. Credentials that have been previously used (e.g. PSL matches) are + // checked to see if they are valid account creation forms. + if (!pending_credentials_.blacklisted_by_user) { + if (pending_credentials_.times_used == 0) { + UploadPasswordForm(pending_credentials_.form_data, autofill::PASSWORD); + } else { + CheckForAccountCreationForm(pending_credentials_, observed_form_); + } + } pending_credentials_.date_created = Time::Now(); SanitizePossibleUsernames(&pending_credentials_); @@ -604,8 +621,7 @@ void PasswordFormManager::UpdateLogin() { return; } - // Update metadata. - ++pending_credentials_.times_used; + UpdateMetadataForUsage(pending_credentials_); if (client_->IsSyncAccountCredential( base::UTF16ToUTF8(pending_credentials_.username_value), @@ -619,10 +635,6 @@ void PasswordFormManager::UpdateLogin() { UpdatePreferredLoginState(password_store); - // Remove alternate usernames. At this point we assume that we have found - // the right username. - pending_credentials_.other_possible_usernames.clear(); - // Update the new preferred login. if (!selected_username_.empty()) { // An other possible username is selected. We set this selected username @@ -675,6 +687,15 @@ void PasswordFormManager::UpdateLogin() { } } +void PasswordFormManager::UpdateMetadataForUsage( + const PasswordForm& credential) { + ++pending_credentials_.times_used; + + // Remove alternate usernames. At this point we assume that we have found + // the right username. + pending_credentials_.other_possible_usernames.clear(); +} + bool PasswordFormManager::UpdatePendingCredentialsIfOtherPossibleUsername( const base::string16& username) { for (PasswordFormMap::const_iterator it = best_matches_.begin(); diff --git a/components/password_manager/core/browser/password_form_manager.h b/components/password_manager/core/browser/password_form_manager.h index 67ac2ea4ccb6f..3037ce6b5fc3c 100644 --- a/components/password_manager/core/browser/password_form_manager.h +++ b/components/password_manager/core/browser/password_form_manager.h @@ -254,6 +254,10 @@ class PasswordFormManager : public PasswordStoreConsumer { bool UpdatePendingCredentialsIfOtherPossibleUsername( const base::string16& username); + // Update state to reflect that |credential| was used. This is broken out from + // UpdateLogin() so that PSL matches can also be properly updated. + void UpdateMetadataForUsage(const autofill::PasswordForm& credential); + // Converts the "ActionsTaken" fields into an int so they can be logged to // UMA. int GetActionsTaken(); 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 c38ed9aad5b18..f81bfbd1fb1ef 100644 --- a/components/password_manager/core/browser/password_form_manager_unittest.cc +++ b/components/password_manager/core/browser/password_form_manager_unittest.cc @@ -34,6 +34,7 @@ using ::testing::Eq; using ::testing::Mock; using ::testing::NiceMock; using ::testing::Return; +using ::testing::SaveArg; namespace password_manager { @@ -170,6 +171,22 @@ class PasswordFormManagerTest : public testing::Test { saved_match_.other_possible_usernames.push_back( ASCIIToUTF16("test2@gmail.com")); + autofill::FormFieldData field; + field.label = ASCIIToUTF16("full_name"); + field.name = ASCIIToUTF16("full_name"); + field.form_control_type = "text"; + saved_match_.form_data.fields.push_back(field); + + field.label = ASCIIToUTF16("Email"); + field.name = ASCIIToUTF16("Email"); + field.form_control_type = "text"; + saved_match_.form_data.fields.push_back(field); + + field.label = ASCIIToUTF16("password"); + field.name = ASCIIToUTF16("password"); + field.form_control_type = "password"; + saved_match_.form_data.fields.push_back(field); + mock_store_ = new NiceMock(); client_.reset(new TestPasswordManagerClient(mock_store_.get())); } @@ -321,6 +338,48 @@ TEST_F(PasswordFormManagerTest, EXPECT_FALSE(manager.IsPendingCredentialsPublicSuffixMatch()); } +TEST_F(PasswordFormManagerTest, PSLMatchedCredentialsMetadataUpdated) { + TestPasswordManagerClient client_with_store(mock_store()); + EXPECT_CALL(*(client_with_store.mock_driver()), IsOffTheRecord()) + .WillRepeatedly(Return(false)); + + TestPasswordManager manager(&client_with_store); + PasswordFormManager form_manager(&manager, + &client_with_store, + client_with_store.mock_driver(), + *observed_form(), + false); + + // The suggestion needs to be PSL-matched. + saved_match()->original_signon_realm = "www.example.org"; + SimulateMatchingPhase(&form_manager, RESULT_MATCH_FOUND); + + PasswordForm submitted_form(*observed_form()); + submitted_form.preferred = true; + submitted_form.username_value = saved_match()->username_value; + submitted_form.password_value = saved_match()->password_value; + submitted_form.origin = saved_match()->origin; + form_manager.ProvisionallySave( + submitted_form, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); + + PasswordForm expected_saved_form(submitted_form); + expected_saved_form.times_used = 1; + expected_saved_form.other_possible_usernames.clear(); + expected_saved_form.form_data = saved_match()->form_data; + PasswordForm actual_saved_form; + + EXPECT_CALL(*(client_with_store.mock_driver()->mock_autofill_manager()), + UploadPasswordForm(_, autofill::ACCOUNT_CREATION_PASSWORD)) + .Times(1); + EXPECT_CALL(*mock_store(), AddLogin(_)) + .WillOnce(SaveArg<0>(&actual_saved_form)); + form_manager.Save(); + + // Can't verify time, so ignore it. + actual_saved_form.date_created = base::Time(); + EXPECT_EQ(expected_saved_form, actual_saved_form); +} + TEST_F(PasswordFormManagerTest, TestNewLoginFromNewPasswordElement) { // Add a new password field to the test form. The PasswordFormManager should // save the password from this field, instead of the current password field. @@ -1132,33 +1191,15 @@ TEST_F(PasswordFormManagerTest, UploadFormData_NewPassword) { EXPECT_CALL(*client_with_store.mock_driver(), IsOffTheRecord()) .WillRepeatedly(Return(false)); - PasswordForm form(*observed_form()); - - autofill::FormFieldData field; - field.label = ASCIIToUTF16("full_name"); - field.name = ASCIIToUTF16("full_name"); - field.form_control_type = "text"; - form.form_data.fields.push_back(field); - - field.label = ASCIIToUTF16("Email"); - field.name = ASCIIToUTF16("Email"); - field.form_control_type = "text"; - form.form_data.fields.push_back(field); - - field.label = ASCIIToUTF16("password"); - field.name = ASCIIToUTF16("password"); - field.form_control_type = "password"; - form.form_data.fields.push_back(field); - // For newly saved passwords, upload a vote for autofill::PASSWORD. PasswordFormManager form_manager(&password_manager, &client_with_store, client_with_store.GetDriver(), - form, + *saved_match(), false); SimulateMatchingPhase(&form_manager, RESULT_NO_MATCH); - PasswordForm form_to_save(form); + PasswordForm form_to_save(*saved_match()); form_to_save.preferred = true; form_to_save.username_value = ASCIIToUTF16("username"); form_to_save.password_value = ASCIIToUTF16("1234"); @@ -1175,7 +1216,7 @@ TEST_F(PasswordFormManagerTest, UploadFormData_NewPassword) { PasswordFormManager blacklist_form_manager(&password_manager, &client_with_store, client_with_store.GetDriver(), - form, + *saved_match(), false); SimulateMatchingPhase(&blacklist_form_manager, RESULT_NO_MATCH); diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index 3859d6889ab2a..32be334f6c0e2 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json @@ -123,7 +123,7 @@ # persistent IDs for all fields (but not for groups!) are needed. These are # specified by the 'id' keys of each policy. NEVER CHANGE EXISTING IDs, # because doing so would break the deployed wire format! -# For your editing convenience: highest ID currently used: 280 +# For your editing convenience: highest ID currently used: 281 # # Placeholders: # The following placeholder strings are automatically substituted: @@ -6955,6 +6955,28 @@ Note that, despite the number, "sslv3" is an earier version than "tls1".''', }, + { + 'name': 'ContextualSearchEnabled', + 'type': 'main', + 'schema': { 'type': 'boolean' }, + 'supported_on': [ + 'android:40-', + ], + 'features': { + 'dynamic_refresh': True, + 'per_profile': True, + }, + 'example_value': True, + 'id': 281, + 'caption': '''Enable Touch to Search''', + 'desc': '''Enables the availability of Touch to Search in $1Google Chrome's content view. + + If you enable this setting, Touch to Search will be available to the user and they can choose to turn the feature on or off. + + If you disable this setting, Touch to Search will be disabled completely. + + If this policy is left not set, it is equivalent to being enabled, see description above.''', + }, ], 'messages': { # Messages that are not associated to any policies. diff --git a/components/rappor/rappor_service.cc b/components/rappor/rappor_service.cc index de814c42affd3..e6879d2981859 100644 --- a/components/rappor/rappor_service.cc +++ b/components/rappor/rappor_service.cc @@ -108,7 +108,7 @@ void RapporService::Start(net::URLRequestContextGetter* request_context, return; DVLOG(1) << "RapporService started. Reporting to " << server_url.spec(); DCHECK(!uploader_); - Initialize(LoadCohort(), LoadSecret(), reporting_level_); + Initialize(LoadCohort(), LoadSecret(), reporting_level); uploader_.reset(new LogUploader(server_url, kMimeType, request_context)); log_rotation_timer_.Start( FROM_HERE, @@ -192,8 +192,10 @@ std::string RapporService::LoadSecret() { } bool RapporService::ExportMetrics(RapporReports* reports) { - if (metrics_map_.empty()) + if (metrics_map_.empty()) { + DVLOG(2) << "metrics_map_ is empty."; return false; + } DCHECK_GE(cohort_, 0); reports->set_cohort(cohort_); @@ -236,8 +238,11 @@ void RapporService::RecordSampleInternal(const std::string& metric_name, DCHECK(IsInitialized()); // Skip this metric if it's reporting level is less than the enabled // reporting level. - if (reporting_level_ < parameters.reporting_level) + if (reporting_level_ < parameters.reporting_level) { + DVLOG(2) << "Metric not logged due to reporting_level " + << reporting_level_ << " < " << parameters.reporting_level; return; + } RapporMetric* metric = LookUpMetric(metric_name, parameters); metric->AddSample(sample); } diff --git a/components/signin/core/common/profile_management_switches.cc b/components/signin/core/common/profile_management_switches.cc index f1a72033047ef..a69675360e829 100644 --- a/components/signin/core/common/profile_management_switches.cc +++ b/components/signin/core/common/profile_management_switches.cc @@ -24,6 +24,12 @@ enum State { }; State GetProcessState() { + // Disables the new avatar menu if the web-based signin is turned on, because + // the new avatar menu always uses the inline signin, which may break some + // SAML users. + if (switches::IsEnableWebBasedSignin()) + return STATE_OLD_AVATAR_MENU; + // Find the state of both command line args. bool is_new_avatar_menu = CommandLine::ForCurrentProcess()->HasSwitch( @@ -126,8 +132,7 @@ bool IsEnableAccountConsistency() { bool IsEnableWebBasedSignin() { return CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableWebBasedSignin) && !IsNewProfileManagement() && - !IsEnableWebviewBasedSignin(); + switches::kEnableWebBasedSignin) && !IsEnableWebviewBasedSignin(); } bool IsEnableWebviewBasedSignin() { diff --git a/components/test/data/password_manager/login_db_v8.sql b/components/test/data/password_manager/login_db_v8.sql new file mode 100644 index 0000000000000..57b4db621e9e6 --- /dev/null +++ b/components/test/data/password_manager/login_db_v8.sql @@ -0,0 +1,11 @@ +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); +INSERT INTO "meta" VALUES('last_compatible_version','1'); +INSERT INTO "meta" VALUES('version','8'); +CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,password_type INTEGER,possible_usernames BLOB,times_used INTEGER,form_data BLOB,use_additional_auth INTEGER,date_synced INTEGER, display_name VARCHAR, avatar_url VARCHAR, federation_url VARCHAR, is_zero_click INTEGER,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm)); +INSERT INTO "logins" VALUES('https://accounts.google.com/ServiceLogin','https://accounts.google.com/ServiceLoginAuth','Email','theerikchen','Passwd',X'','','https://accounts.google.com/',1,1,1402955745,0,0,0,X'00000000',1,X'18000000020000000000000000000000000000000000000000000000',NULL,0,'','','',0); +INSERT INTO "logins" VALUES('https://accounts.google.com/ServiceLogin','https://accounts.google.com/ServiceLoginAuth','Email','theerikchen2','Passwd',X'','','https://accounts.google.com/',1,1,1402950000,0,0,0,X'00000000',1,X'18000000020000000000000000000000000000000000000000000000',NULL,0,'','','',0); +CREATE INDEX logins_signon ON logins (signon_realm); +COMMIT; + diff --git a/content/app/content_main_runner.cc b/content/app/content_main_runner.cc index 05e45bd791c07..1b03316475582 100644 --- a/content/app/content_main_runner.cc +++ b/content/app/content_main_runner.cc @@ -765,6 +765,15 @@ class ContentMainRunnerImpl : public ContentMainRunner { if (delegate_) delegate_->SandboxInitialized(process_type); +#if defined(OS_TIZEN_MOBILE) + if (process_type.empty()) + StoreArgvPointerAddress(argv); + else + SetProcessTitleFromCommandLine(argv); +#elif defined(OS_POSIX) && !defined(OS_IOS) && !defined(OS_ANDROID) + SetProcessTitleFromCommandLine(argv); +#endif + // Return -1 to indicate no early termination. return -1; } diff --git a/content/app/resources/content_resources.grd b/content/app/resources/content_resources.grd index 0c189f37db9f3..9c4373b47a13b 100644 --- a/content/app/resources/content_resources.grd +++ b/content/app/resources/content_resources.grd @@ -47,6 +47,7 @@ + diff --git a/content/app/resources/default_100_percent/mediaplayer_cast_off.png b/content/app/resources/default_100_percent/mediaplayer_cast_off.png index e16f58e57a69b..050022d2fe5b8 100644 Binary files a/content/app/resources/default_100_percent/mediaplayer_cast_off.png and b/content/app/resources/default_100_percent/mediaplayer_cast_off.png differ diff --git a/content/app/resources/default_100_percent/mediaplayer_overlay_cast_off.png b/content/app/resources/default_100_percent/mediaplayer_overlay_cast_off.png new file mode 100644 index 0000000000000..e16f58e57a69b Binary files /dev/null and b/content/app/resources/default_100_percent/mediaplayer_overlay_cast_off.png differ diff --git a/content/browser/accessibility/android_granularity_movement_browsertest.cc b/content/browser/accessibility/android_granularity_movement_browsertest.cc index be185f264b48d..975da4ceeb8db 100644 --- a/content/browser/accessibility/android_granularity_movement_browsertest.cc +++ b/content/browser/accessibility/android_granularity_movement_browsertest.cc @@ -51,8 +51,13 @@ class AndroidGranularityMovementBrowserTest : public ContentBrowserTest { return web_contents->GetRootBrowserAccessibilityManager()->GetRoot(); } - // Call NextAtGranularity repeatedly and return a string that concatenates - // all of the text of the returned text ranges. + // First, set accessibility focus to a node and wait for the update that + // loads inline text boxes for that node. (We load inline text boxes + // asynchronously on Android since we only ever need them for the node + // with accessibility focus.) + // + // Then call NextAtGranularity repeatedly and return a string that + // concatenates all of the text of the returned text ranges. // // As an example, if the node's text is "cat dog" and you traverse by // word, this returns "'cat', 'dog'". @@ -64,6 +69,13 @@ class AndroidGranularityMovementBrowserTest : public ContentBrowserTest { base::string16 TraverseNodeAtGranularity( BrowserAccessibility* node, int granularity) { + AccessibilityNotificationWaiter waiter( + shell(), AccessibilityModeComplete, + ui::AX_EVENT_TREE_CHANGED); + node->manager()->delegate()->AccessibilitySetAccessibilityFocus( + node->GetId()); + waiter.WaitForNotification(); + int start_index = -1; int end_index = -1; BrowserAccessibilityAndroid* android_node = diff --git a/content/browser/accessibility/browser_accessibility_android.cc b/content/browser/accessibility/browser_accessibility_android.cc index 4ab0e6e6e1590..53189cbf1d11b 100644 --- a/content/browser/accessibility/browser_accessibility_android.cc +++ b/content/browser/accessibility/browser_accessibility_android.cc @@ -6,6 +6,7 @@ #include "base/i18n/break_iterator.h" #include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "content/browser/accessibility/browser_accessibility_manager_android.h" #include "content/common/accessibility_messages.h" @@ -76,6 +77,10 @@ bool BrowserAccessibilityAndroid::PlatformIsLeaf() const { if (HasFocusableChild()) return false; + // Date and time controls should drop their children. + if (GetRole() == ui::AX_ROLE_DATE || GetRole() == ui::AX_ROLE_TIME) + return true; + // Headings with text can drop their children. base::string16 name = GetText(); if (GetRole() == ui::AX_ROLE_HEADING && !name.empty()) @@ -92,6 +97,24 @@ bool BrowserAccessibilityAndroid::PlatformIsLeaf() const { return BrowserAccessibility::PlatformIsLeaf(); } +bool BrowserAccessibilityAndroid::CanScrollForward() const { + if (!IsSlider()) + return false; + + float value = GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE); + float max = GetFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE); + return value < max; +} + +bool BrowserAccessibilityAndroid::CanScrollBackward() const { + if (!IsSlider()) + return false; + + float value = GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE); + float min = GetFloatAttribute(ui::AX_ATTR_MIN_VALUE_FOR_RANGE); + return value > min; +} + bool BrowserAccessibilityAndroid::IsCheckable() const { bool checkable = false; bool is_aria_pressed_defined; @@ -208,6 +231,10 @@ bool BrowserAccessibilityAndroid::IsSelected() const { return HasState(ui::AX_STATE_SELECTED); } +bool BrowserAccessibilityAndroid::IsSlider() const { + return GetRole() == ui::AX_ROLE_SLIDER; +} + bool BrowserAccessibilityAndroid::IsVisibleToUser() const { return !HasState(ui::AX_STATE_INVISIBLE); } @@ -229,12 +256,15 @@ const char* BrowserAccessibilityAndroid::GetClassName() const { case ui::AX_ROLE_SLIDER: class_name = "android.widget.SeekBar"; break; + case ui::AX_ROLE_COLOR_WELL: case ui::AX_ROLE_COMBO_BOX: + case ui::AX_ROLE_DATE: + case ui::AX_ROLE_POP_UP_BUTTON: + case ui::AX_ROLE_TIME: class_name = "android.widget.Spinner"; break; case ui::AX_ROLE_BUTTON: case ui::AX_ROLE_MENU_BUTTON: - case ui::AX_ROLE_POP_UP_BUTTON: class_name = "android.widget.Button"; break; case ui::AX_ROLE_CHECK_BOX: @@ -297,13 +327,29 @@ base::string16 BrowserAccessibilityAndroid::GetText() const { // name on Android, not 2 or 3 like on Windows or Mac. // First, always return the |value| attribute if this is an - // editable text field. - if (!value().empty() && - (GetRole() == ui::AX_ROLE_EDITABLE_TEXT || - GetRole() == ui::AX_ROLE_TEXT_AREA || - GetRole() == ui::AX_ROLE_TEXT_FIELD || - HasState(ui::AX_STATE_EDITABLE))) { - return base::UTF8ToUTF16(value()); + // input field. + if (!value().empty()) { + if (HasState(ui::AX_STATE_EDITABLE)) + return base::UTF8ToUTF16(value()); + + switch (GetRole()) { + case ui::AX_ROLE_COMBO_BOX: + case ui::AX_ROLE_EDITABLE_TEXT: + case ui::AX_ROLE_POP_UP_BUTTON: + case ui::AX_ROLE_TEXT_AREA: + case ui::AX_ROLE_TEXT_FIELD: + return base::UTF8ToUTF16(value()); + } + } + + // For color wells, the color is stored in separate attributes. + // Perhaps we could return color names in the future? + if (GetRole() == ui::AX_ROLE_COLOR_WELL) { + int red = GetIntAttribute(ui::AX_ATTR_COLOR_VALUE_RED); + int green = GetIntAttribute(ui::AX_ATTR_COLOR_VALUE_GREEN); + int blue = GetIntAttribute(ui::AX_ATTR_COLOR_VALUE_BLUE); + return base::UTF8ToUTF16( + base::StringPrintf("#%02X%02X%02X", red, green, blue)); } // Always prefer visible text if this is a link. Sites sometimes add @@ -321,8 +367,17 @@ base::string16 BrowserAccessibilityAndroid::GetText() const { // Blink, making the platform-specific mapping to accessible text simpler. base::string16 description = GetString16Attribute(ui::AX_ATTR_DESCRIPTION); base::string16 help = GetString16Attribute(ui::AX_ATTR_HELP); + base::string16 placeholder; - GetHtmlAttribute("placeholder", &placeholder); + switch (GetRole()) { + case ui::AX_ROLE_DATE: + case ui::AX_ROLE_EDITABLE_TEXT: + case ui::AX_ROLE_TEXT_AREA: + case ui::AX_ROLE_TEXT_FIELD: + case ui::AX_ROLE_TIME: + GetHtmlAttribute("placeholder", &placeholder); + } + int title_elem_id = GetIntAttribute( ui::AX_ATTR_TITLE_UI_ELEMENT); base::string16 text; @@ -334,7 +389,7 @@ base::string16 BrowserAccessibilityAndroid::GetText() const { text = help; else if (!name().empty()) text = base::UTF8ToUTF16(name()); - else if (GetRole() == ui::AX_ROLE_TEXT_FIELD && !placeholder.empty()) + else if (!placeholder.empty()) text = placeholder; else if (!value().empty()) text = base::UTF8ToUTF16(value()); @@ -383,11 +438,13 @@ int BrowserAccessibilityAndroid::GetItemIndex() const { break; case ui::AX_ROLE_SLIDER: case ui::AX_ROLE_PROGRESS_INDICATOR: { - float value_for_range; - if (GetFloatAttribute( - ui::AX_ATTR_VALUE_FOR_RANGE, &value_for_range)) { - index = static_cast(value_for_range); - } + // Return a percentage here for live feedback in an AccessibilityEvent. + // The exact value is returned in RangeCurrentValue. + float min = GetFloatAttribute(ui::AX_ATTR_MIN_VALUE_FOR_RANGE); + float max = GetFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE); + float value = GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE); + if (max > min && value >= min && value <= max) + index = static_cast(((value - min)) * 100 / (max - min)); break; } } @@ -403,14 +460,12 @@ int BrowserAccessibilityAndroid::GetItemCount() const { count = PlatformChildCount(); break; case ui::AX_ROLE_SLIDER: - case ui::AX_ROLE_PROGRESS_INDICATOR: { - float max_value_for_range; - if (GetFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE, - &max_value_for_range)) { - count = static_cast(max_value_for_range); - } + case ui::AX_ROLE_PROGRESS_INDICATOR: + // An AccessibilityEvent can only return integer information about a + // seek control, so we return a percentage. The real range is returned + // in RangeMin and RangeMax. + count = 100; break; - } } return count; } diff --git a/content/browser/accessibility/browser_accessibility_android.h b/content/browser/accessibility/browser_accessibility_android.h index 8dc21261944a1..70579ab9b85cf 100644 --- a/content/browser/accessibility/browser_accessibility_android.h +++ b/content/browser/accessibility/browser_accessibility_android.h @@ -19,6 +19,8 @@ class CONTENT_EXPORT BrowserAccessibilityAndroid : public BrowserAccessibility { virtual bool PlatformIsLeaf() const override; + bool CanScrollForward() const; + bool CanScrollBackward() const; bool IsCheckable() const; bool IsChecked() const; bool IsClickable() const; @@ -38,6 +40,7 @@ class CONTENT_EXPORT BrowserAccessibilityAndroid : public BrowserAccessibility { bool IsRangeType() const; bool IsScrollable() const; bool IsSelected() const; + bool IsSlider() const; bool IsVisibleToUser() const; bool CanOpenPopup() const; diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h index f07814c0d5085..c0e59fa1d6854 100644 --- a/content/browser/accessibility/browser_accessibility_manager.h +++ b/content/browser/accessibility/browser_accessibility_manager.h @@ -69,6 +69,7 @@ class CONTENT_EXPORT BrowserAccessibilityDelegate { const gfx::Rect& bounds) const = 0; virtual void AccessibilityHitTest( const gfx::Point& point) = 0; + virtual void AccessibilitySetAccessibilityFocus(int acc_obj_id) = 0; virtual void AccessibilityFatalError() = 0; virtual gfx::AcceleratedWidget AccessibilityGetAcceleratedWidget() = 0; virtual gfx::NativeViewAccessible AccessibilityGetNativeViewAccessible() = 0; diff --git a/content/browser/accessibility/browser_accessibility_manager_android.cc b/content/browser/accessibility/browser_accessibility_manager_android.cc index 45c5026f11881..fd4e0ff9fae10 100644 --- a/content/browser/accessibility/browser_accessibility_manager_android.cc +++ b/content/browser/accessibility/browser_accessibility_manager_android.cc @@ -116,9 +116,15 @@ void BrowserAccessibilityManagerAndroid::NotifyAccessibilityEvent( if (obj.is_null()) return; + BrowserAccessibilityAndroid* android_node = + static_cast(node); + if (event_type == ui::AX_EVENT_HIDE) return; + if (event_type == ui::AX_EVENT_TREE_CHANGED) + return; + if (event_type == ui::AX_EVENT_HOVER) { HandleHoverEvent(node); return; @@ -157,8 +163,6 @@ void BrowserAccessibilityManagerAndroid::NotifyAccessibilityEvent( case ui::AX_EVENT_SHOW: { // This event is fired when an object appears in a live region. // Speak its text. - BrowserAccessibilityAndroid* android_node = - static_cast(node); Java_BrowserAccessibilityManager_announceLiveRegionText( env, obj.obj(), base::android::ConvertUTF16ToJavaString( @@ -175,6 +179,9 @@ void BrowserAccessibilityManagerAndroid::NotifyAccessibilityEvent( if (node->IsEditableText()) { Java_BrowserAccessibilityManager_handleEditableTextChanged( env, obj.obj(), node->GetId()); + } else if (android_node->IsSlider()) { + Java_BrowserAccessibilityManager_handleSliderChanged( + env, obj.obj(), node->GetId()); } break; default: @@ -247,6 +254,8 @@ jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityNodeInfo( Java_BrowserAccessibilityManager_setAccessibilityNodeInfoBooleanAttributes( env, obj, info, id, + node->CanScrollForward(), + node->CanScrollBackward(), node->IsCheckable(), node->IsChecked(), node->IsClickable(), @@ -261,10 +270,13 @@ jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityNodeInfo( Java_BrowserAccessibilityManager_setAccessibilityNodeInfoClassName( env, obj, info, base::android::ConvertUTF8ToJavaString(env, node->GetClassName()).obj()); - Java_BrowserAccessibilityManager_setAccessibilityNodeInfoContentDescription( - env, obj, info, - base::android::ConvertUTF16ToJavaString(env, node->GetText()).obj(), - node->IsLink()); + if (!node->IsPassword() || + Java_BrowserAccessibilityManager_shouldExposePasswordText(env, obj)) { + Java_BrowserAccessibilityManager_setAccessibilityNodeInfoContentDescription( + env, obj, info, + base::android::ConvertUTF16ToJavaString(env, node->GetText()).obj(), + node->IsLink()); + } gfx::Rect absolute_rect = node->GetLocalBoundsRect(); gfx::Rect parent_relative_rect = absolute_rect; @@ -346,24 +358,37 @@ jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityEvent( node->GetMaxScrollY()); switch (event_type) { - case ANDROID_ACCESSIBILITY_EVENT_TEXT_CHANGED: + case ANDROID_ACCESSIBILITY_EVENT_TEXT_CHANGED: { + base::string16 before_text, text; + if (!node->IsPassword() || + Java_BrowserAccessibilityManager_shouldExposePasswordText(env, obj)) { + before_text = node->GetTextChangeBeforeText(); + text = node->GetText(); + } Java_BrowserAccessibilityManager_setAccessibilityEventTextChangedAttrs( env, obj, event, node->GetTextChangeFromIndex(), node->GetTextChangeAddedCount(), node->GetTextChangeRemovedCount(), base::android::ConvertUTF16ToJavaString( - env, node->GetTextChangeBeforeText()).obj(), - base::android::ConvertUTF16ToJavaString(env, node->GetText()).obj()); + env, before_text).obj(), + base::android::ConvertUTF16ToJavaString(env, text).obj()); break; - case ANDROID_ACCESSIBILITY_EVENT_TEXT_SELECTION_CHANGED: + } + case ANDROID_ACCESSIBILITY_EVENT_TEXT_SELECTION_CHANGED: { + base::string16 text; + if (!node->IsPassword() || + Java_BrowserAccessibilityManager_shouldExposePasswordText(env, obj)) { + text = node->GetText(); + } Java_BrowserAccessibilityManager_setAccessibilityEventSelectionAttrs( env, obj, event, node->GetSelectionStart(), node->GetSelectionEnd(), node->GetEditableTextLength(), - base::android::ConvertUTF16ToJavaString(env, node->GetText()).obj()); + base::android::ConvertUTF16ToJavaString(env, text).obj()); break; + } default: break; } @@ -449,6 +474,38 @@ void BrowserAccessibilityManagerAndroid::SetSelection( SetTextSelection(*node, start, end); } +jboolean BrowserAccessibilityManagerAndroid::AdjustSlider( + JNIEnv* env, jobject obj, jint id, jboolean increment) { + BrowserAccessibility* node = GetFromID(id); + if (!node) + return false; + + BrowserAccessibilityAndroid* android_node = + static_cast(node); + + if (!android_node->IsSlider() || !android_node->IsEnabled()) + return false; + + float value = node->GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE); + float min = node->GetFloatAttribute(ui::AX_ATTR_MIN_VALUE_FOR_RANGE); + float max = node->GetFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE); + if (max <= min) + return false; + + // To behave similarly to an Android SeekBar, move by an increment of + // approximately 20%. + float original_value = value; + float delta = (max - min) / 5.0f; + value += (increment ? delta : -delta); + value = std::max(std::min(value, max), min); + if (value != original_value) { + BrowserAccessibilityManager::SetValue( + *node, base::UTF8ToUTF16(base::DoubleToString(value))); + return true; + } + return false; +} + void BrowserAccessibilityManagerAndroid::HandleHoverEvent( BrowserAccessibility* node) { JNIEnv* env = AttachCurrentThread(); @@ -541,9 +598,14 @@ jboolean BrowserAccessibilityManagerAndroid::NextAtGranularity( int end_index = -1; if (NextAtGranularity(granularity, cursor_index, node, &start_index, &end_index)) { + base::string16 text; + if (!node->IsPassword() || + Java_BrowserAccessibilityManager_shouldExposePasswordText(env, obj)) { + text = node->GetText(); + } Java_BrowserAccessibilityManager_finishGranularityMove( env, obj, base::android::ConvertUTF16ToJavaString( - env, node->GetText()).obj(), + env, text).obj(), extend_selection, start_index, end_index, true); return true; } @@ -656,6 +718,12 @@ bool BrowserAccessibilityManagerAndroid::PreviousAtGranularity( return true; } +void BrowserAccessibilityManagerAndroid::SetAccessibilityFocus( + JNIEnv* env, jobject obj, jint id) { + if (delegate_) + delegate_->AccessibilitySetAccessibilityFocus(id); +} + void BrowserAccessibilityManagerAndroid::OnRootChanged(ui::AXNode* new_root) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef obj = java_ref_.get(env); diff --git a/content/browser/accessibility/browser_accessibility_manager_android.h b/content/browser/accessibility/browser_accessibility_manager_android.h index 63d3268e231ca..f0e2d344ac12e 100644 --- a/content/browser/accessibility/browser_accessibility_manager_android.h +++ b/content/browser/accessibility/browser_accessibility_manager_android.h @@ -79,6 +79,7 @@ class CONTENT_EXPORT BrowserAccessibilityManagerAndroid void ScrollToMakeNodeVisible(JNIEnv* env, jobject obj, jint id); void SetTextFieldValue(JNIEnv* env, jobject obj, jint id, jstring value); void SetSelection(JNIEnv* env, jobject obj, jint id, jint start, jint end); + jboolean AdjustSlider(JNIEnv* env, jobject obj, jint id, jboolean increment); // Return the id of the next node in tree order in the direction given by // |forwards|, starting with |start_id|, that matches |element_type|, @@ -115,6 +116,11 @@ class CONTENT_EXPORT BrowserAccessibilityManagerAndroid int32 granularity, int cursor_index, BrowserAccessibilityAndroid* node, int32* start_index, int32* end_index); + // Set accessibility focus. This sends a message to the renderer to + // asynchronously load inline text boxes for this node only, enabling more + // accurate movement by granularities on this node. + void SetAccessibilityFocus(JNIEnv* env, jobject obj, jint id); + protected: // AXTreeDelegate overrides. virtual void OnRootChanged(ui::AXNode* new_root) override; diff --git a/content/browser/accessibility/browser_accessibility_manager_unittest.cc b/content/browser/accessibility/browser_accessibility_manager_unittest.cc index b71187c69bb72..8e2e3d033b9a5 100644 --- a/content/browser/accessibility/browser_accessibility_manager_unittest.cc +++ b/content/browser/accessibility/browser_accessibility_manager_unittest.cc @@ -82,6 +82,7 @@ class TestBrowserAccessibilityDelegate return gfx::Point(); } void AccessibilityHitTest(const gfx::Point& point) override {} + void AccessibilitySetAccessibilityFocus(int acc_obj_id) override {} void AccessibilityFatalError() override { got_fatal_error_ = true; } gfx::AcceleratedWidget AccessibilityGetAcceleratedWidget() override { return gfx::kNullAcceleratedWidget; diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc index 9aa69cdf7daa3..12117bf5dfb55 100644 --- a/content/browser/android/content_view_core_impl.cc +++ b/content/browser/android/content_view_core_impl.cc @@ -1086,15 +1086,23 @@ void ContentViewCoreImpl::SelectBetweenCoordinates(JNIEnv* env, jobject obj, void ContentViewCoreImpl::MoveCaret(JNIEnv* env, jobject obj, jfloat x, jfloat y) { - if (GetRenderWidgetHostViewAndroid()) { - GetRenderWidgetHostViewAndroid()->MoveCaret( - gfx::Point(x / dpi_scale_, y / dpi_scale_)); - } + RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid(); + if (rwhv) + rwhv->MoveCaret(gfx::Point(x / dpi_scale_, y / dpi_scale_)); } -void ContentViewCoreImpl::HideTextHandles(JNIEnv* env, jobject obj) { - if (GetRenderWidgetHostViewAndroid()) - GetRenderWidgetHostViewAndroid()->HideTextHandles(); +void ContentViewCoreImpl::DismissTextHandles(JNIEnv* env, jobject obj) { + RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid(); + if (rwhv) + rwhv->DismissTextHandles(); +} + +void ContentViewCoreImpl::SetTextHandlesTemporarilyHidden(JNIEnv* env, + jobject obj, + jboolean hidden) { + RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid(); + if (rwhv) + rwhv->SetTextHandlesTemporarilyHidden(hidden); } void ContentViewCoreImpl::ResetGestureDetection(JNIEnv* env, jobject obj) { diff --git a/content/browser/android/content_view_core_impl.h b/content/browser/android/content_view_core_impl.h index 6e906960d07bd..8a823ee72b8c0 100644 --- a/content/browser/android/content_view_core_impl.h +++ b/content/browser/android/content_view_core_impl.h @@ -143,7 +143,10 @@ class ContentViewCoreImpl : public ContentViewCore, jfloat x1, jfloat y1, jfloat x2, jfloat y2); void MoveCaret(JNIEnv* env, jobject obj, jfloat x, jfloat y); - void HideTextHandles(JNIEnv* env, jobject obj); + void DismissTextHandles(JNIEnv* env, jobject obj); + void SetTextHandlesTemporarilyHidden(JNIEnv* env, + jobject obj, + jboolean hidden); void ResetGestureDetection(JNIEnv* env, jobject obj); void SetDoubleTapSupportEnabled(JNIEnv* env, jobject obj, jboolean enabled); diff --git a/content/browser/android/java/gin_java_bridge_dispatcher_host.cc b/content/browser/android/java/gin_java_bridge_dispatcher_host.cc index c0b20b975abde..c8fb2fd989962 100644 --- a/content/browser/android/java/gin_java_bridge_dispatcher_host.cc +++ b/content/browser/android/java/gin_java_bridge_dispatcher_host.cc @@ -210,18 +210,10 @@ void GinJavaBridgeDispatcherHost::RemoveNamedObject( named_objects_.erase(iter); object->RemoveName(); - // Not erasing from the objects map, as we can still receive method - // invocation requests for this object, and they should work until the - // java object is gone. - if (!object->IsNamed()) { - JNIEnv* env = base::android::AttachCurrentThread(); - base::android::ScopedJavaLocalRef retained_object_set = - retained_object_set_.get(env); - if (!retained_object_set.is_null()) { - JNI_Java_HashSet_remove( - env, retained_object_set, object->GetLocalRef(env)); - } - } + // As the object isn't going to be removed from the JavaScript side until the + // next page reload, calls to it must still work, thus we should continue to + // hold it. All the transient objects and removed named objects will be purged + // during the cleansing caused by DocumentAvailableInMainFrame event. web_contents()->SendToAllFrames( new GinJavaBridgeMsg_RemoveNamedObject(MSG_ROUTING_NONE, copied_name)); diff --git a/content/browser/android/java/jni_helper.cc b/content/browser/android/java/jni_helper.cc index 09026e77952a3..f83b30835393a 100644 --- a/content/browser/android/java/jni_helper.cc +++ b/content/browser/android/java/jni_helper.cc @@ -48,6 +48,16 @@ base::LazyInstance g_method_id_map = LAZY_INSTANCE_INITIALIZER; } // namespace +jfieldID GetFieldID(JNIEnv* env, + const base::android::JavaRef& clazz, + const char* field_name, + const char* jni_signature) { + jfieldID field_id = env->GetFieldID(clazz.obj(), field_name, jni_signature); + CHECK(!base::android::ClearException(env) && field_id) << + "Failed to find field " << field_name << " " << jni_signature; + return field_id; +} + jmethodID GetMethodIDFromClassName(JNIEnv* env, const char* class_name, const char* method, diff --git a/content/browser/android/java/jni_helper.h b/content/browser/android/java/jni_helper.h index 25c851598fb20..84f837d98bf5d 100644 --- a/content/browser/android/java/jni_helper.h +++ b/content/browser/android/java/jni_helper.h @@ -7,6 +7,7 @@ #include +#include "base/android/scoped_java_ref.h" #include "content/common/content_export.h" namespace content { @@ -22,6 +23,13 @@ CONTENT_EXPORT jmethodID GetMethodIDFromClassName(JNIEnv* env, const char* method, const char* jni_signature); +// Gets the field ID for a class field. +// This method triggers a fatal assertion if the field could not be found. +CONTENT_EXPORT jfieldID GetFieldID(JNIEnv* env, + const base::android::JavaRef& clazz, + const char* field_name, + const char* jni_signature); + } // namespace content #endif // CONTENT_BROWSER_ANDROID_JAVA_JNI_HELPER_H_ diff --git a/content/browser/android/popup_touch_handle_drawable.cc b/content/browser/android/popup_touch_handle_drawable.cc index ac2f57bffc2d5..8a7cf845f70e6 100644 --- a/content/browser/android/popup_touch_handle_drawable.cc +++ b/content/browser/android/popup_touch_handle_drawable.cc @@ -16,6 +16,9 @@ PopupTouchHandleDrawable::PopupTouchHandleDrawable( } PopupTouchHandleDrawable::~PopupTouchHandleDrawable() { + // Explicitly disabling ensures that any external references to the Java + // object are cleared, allowing it to be GC'ed in a timely fashion. + SetEnabled(false); } void PopupTouchHandleDrawable::SetEnabled(bool enabled) { diff --git a/content/browser/compositor/io_surface_layer_mac.mm b/content/browser/compositor/io_surface_layer_mac.mm index d09f24c490265..8dacd43abe379 100644 --- a/content/browser/compositor/io_surface_layer_mac.mm +++ b/content/browser/compositor/io_surface_layer_mac.mm @@ -9,6 +9,7 @@ #include #include #include +#include #include "base/mac/mac_util.h" #include "base/mac/sdk_forward_declarations.h" diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index f66fad6225636..b7941077c5eb8 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc @@ -471,6 +471,10 @@ void RenderFrameHostImpl::AccessibilityHitTest(const gfx::Point& point) { Send(new AccessibilityMsg_HitTest(routing_id_, point)); } +void RenderFrameHostImpl::AccessibilitySetAccessibilityFocus(int acc_obj_id) { + Send(new AccessibilityMsg_SetAccessibilityFocus(routing_id_, acc_obj_id)); +} + void RenderFrameHostImpl::AccessibilityFatalError() { browser_accessibility_manager_.reset(NULL); if (accessibility_reset_token_) @@ -1035,10 +1039,9 @@ void RenderFrameHostImpl::OnShowDesktopNotification( } void RenderFrameHostImpl::OnCancelDesktopNotification(int notification_id) { - if (!cancel_notification_callbacks_.count(notification_id)) { - NOTREACHED(); + if (!cancel_notification_callbacks_.count(notification_id)) return; - } + cancel_notification_callbacks_[notification_id].Run(); cancel_notification_callbacks_.erase(notification_id); } diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h index feab5a373a325..b1c470312f443 100644 --- a/content/browser/frame_host/render_frame_host_impl.h +++ b/content/browser/frame_host/render_frame_host_impl.h @@ -143,6 +143,7 @@ class CONTENT_EXPORT RenderFrameHostImpl gfx::Point AccessibilityOriginInScreen( const gfx::Rect& bounds) const override; void AccessibilityHitTest(const gfx::Point& point) override; + void AccessibilitySetAccessibilityFocus(int acc_obj_id) override; void AccessibilityFatalError() override; gfx::AcceleratedWidget AccessibilityGetAcceleratedWidget() override; gfx::NativeViewAccessible AccessibilityGetNativeViewAccessible() override; diff --git a/content/browser/plugin_service_impl.cc b/content/browser/plugin_service_impl.cc index 176e80e58eb61..49b66389dd370 100644 --- a/content/browser/plugin_service_impl.cc +++ b/content/browser/plugin_service_impl.cc @@ -200,7 +200,7 @@ void PluginServiceImpl::StartWatchingPlugins() { KEY_NOTIFY) == ERROR_SUCCESS) { base::win::RegKey::ChangeCallback callback = base::Bind(&PluginServiceImpl::OnKeyChanged, base::Unretained(this), - base::Unretained(&hkcu_key_)); + base::Unretained(&hklm_key_)); hklm_key_.StartWatching(callback); } #endif @@ -630,7 +630,7 @@ void PluginServiceImpl::GetPluginsOnIOThread( void PluginServiceImpl::OnKeyChanged(base::win::RegKey* key) { key->StartWatching(base::Bind(&PluginServiceImpl::OnKeyChanged, base::Unretained(this), - base::Unretained(&hkcu_key_))); + base::Unretained(key))); PluginList::Singleton()->RefreshPlugins(); PurgePluginListCache(NULL, false); diff --git a/content/browser/renderer_host/media/audio_renderer_host.cc b/content/browser/renderer_host/media/audio_renderer_host.cc index 43555fcdb199d..a8939abf9bbd2 100644 --- a/content/browser/renderer_host/media/audio_renderer_host.cc +++ b/content/browser/renderer_host/media/audio_renderer_host.cc @@ -67,6 +67,11 @@ class AudioRendererHost::AudioEntry bool playing() const { return playing_; } void set_playing(bool playing) { playing_ = playing; } +#if defined(OS_TIZEN) + std::string app_id() const override { return host_->app_id_; } + std::string app_class() const override { return host_->app_class_; } +#endif + private: // media::AudioOutputController::EventHandler implementation. void OnCreated() override; @@ -511,4 +516,13 @@ bool AudioRendererHost::RenderViewHasActiveAudio(int render_view_id) const { return false; } +#if defined(OS_TIZEN) +void AudioRendererHost::SetMediaStreamProperties( + const std::string& app_id, + const std::string& app_class) { + app_id_ = app_id; + app_class_ = app_class; +} +#endif + } // namespace content diff --git a/content/browser/renderer_host/media/audio_renderer_host.h b/content/browser/renderer_host/media/audio_renderer_host.h index 11bc13f3900fb..d38a7e9cc5744 100644 --- a/content/browser/renderer_host/media/audio_renderer_host.h +++ b/content/browser/renderer_host/media/audio_renderer_host.h @@ -38,6 +38,9 @@ #define CONTENT_BROWSER_RENDERER_HOST_MEDIA_AUDIO_RENDERER_HOST_H_ #include +#if defined(OS_TIZEN) +#include +#endif #include "base/atomic_ref_count.h" #include "base/gtest_prod_util.h" @@ -93,6 +96,15 @@ class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter { // |render_view_id| are actively playing. Can be called from any thread. bool RenderViewHasActiveAudio(int render_view_id) const; +#if defined(OS_TIZEN) + // Sets an application ID and class properties, which are used to tag audio + // streams in pulseaudio/Murphy. + virtual void SetMediaStreamProperties(const std::string& app_id, + const std::string& app_class); + const std::string& app_id() const { return app_id_; } + const std::string& app_class() const { return app_class_; } +#endif + private: friend class AudioRendererHostTest; friend class BrowserThread; @@ -181,6 +193,12 @@ class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter { // The number of streams in the playing state. base::AtomicRefCount num_playing_streams_; +#if defined(OS_TIZEN) + // Application ID and class for the Murphy resource set. + std::string app_id_; + std::string app_class_; +#endif + DISALLOW_COPY_AND_ASSIGN(AudioRendererHost); }; diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index be30e9224fa33..c582a6e97a653 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc @@ -1126,6 +1126,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer( switches::kEnableGPUClientLogging, switches::kEnableGpuClientTracing, switches::kEnableGPUServiceLogging, + switches::kEnableLinkDisambiguationPopup, switches::kEnableLowResTiling, switches::kEnableInbandTextTracks, switches::kEnableLCDText, diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc index 01a5e1bb5d8b4..29f70c3f5bec7 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc @@ -93,6 +93,10 @@ #include "content/browser/media/media_web_contents_observer.h" #endif +#if defined(OS_TIZEN) && defined(ENABLE_MURPHY) +#include "xwalk/tizen/browser/media/media_webcontents_observer.h" +#endif + using base::TimeDelta; using blink::WebConsoleMessage; using blink::WebDragOperation; @@ -219,6 +223,10 @@ RenderViewHostImpl::RenderViewHostImpl( #if defined(ENABLE_BROWSER_CDMS) media_web_contents_observer_.reset(new MediaWebContentsObserver(this)); #endif + +#if defined(OS_TIZEN) && defined(ENABLE_MURPHY) + media_webcontents_observer_.reset(new tizen::MediaWebContentsObserver(this)); +#endif } RenderViewHostImpl::~RenderViewHostImpl() { diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h index c6fdf055b0d0b..e806a42e57ff3 100644 --- a/content/browser/renderer_host/render_view_host_impl.h +++ b/content/browser/renderer_host/render_view_host_impl.h @@ -34,6 +34,12 @@ struct MediaPlayerAction; struct ViewHostMsg_CreateWindow_Params; struct ViewMsg_PostMessage_Params; +#if defined(OS_TIZEN) && defined(ENABLE_MURPHY) +namespace tizen { +class MediaWebContentsObserver; +} +#endif + namespace base { class ListValue; } @@ -453,6 +459,11 @@ class CONTENT_EXPORT RenderViewHostImpl scoped_ptr media_web_contents_observer_; #endif +#if defined(OS_TIZEN) && defined(ENABLE_MURPHY) + // Manages all the media player managers and forwards IPCs to them. + scoped_ptr media_webcontents_observer_; +#endif + // True if the current focused element is editable. bool is_focused_element_editable_; diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index 3a2dc883f4031..e8a4f55e0c84b 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc @@ -477,8 +477,6 @@ void RenderWidgetHostViewAndroid::Focus() { host_->SetInputMethodActive(true); if (overscroll_effect_) overscroll_effect_->Enable(); - if (selection_controller_) - selection_controller_->SetTemporarilyHidden(false); } void RenderWidgetHostViewAndroid::Blur() { @@ -486,8 +484,6 @@ void RenderWidgetHostViewAndroid::Blur() { host_->Blur(); if (overscroll_effect_) overscroll_effect_->Disable(); - if (selection_controller_) - selection_controller_->SetTemporarilyHidden(true); } bool RenderWidgetHostViewAndroid::HasFocus() const { @@ -1517,11 +1513,16 @@ void RenderWidgetHostViewAndroid::MoveCaret(const gfx::Point& point) { host_->MoveCaret(point); } -void RenderWidgetHostViewAndroid::HideTextHandles() { +void RenderWidgetHostViewAndroid::DismissTextHandles() { if (selection_controller_) selection_controller_->HideAndDisallowShowingAutomatically(); } +void RenderWidgetHostViewAndroid::SetTextHandlesTemporarilyHidden(bool hidden) { + if (selection_controller_) + selection_controller_->SetTemporarilyHidden(hidden); +} + void RenderWidgetHostViewAndroid::OnShowingPastePopup( const gfx::PointF& point) { if (!selection_controller_) @@ -1536,7 +1537,7 @@ void RenderWidgetHostViewAndroid::OnShowingPastePopup( insertion_bound.visible = true; insertion_bound.edge_top = point; insertion_bound.edge_bottom = point; - HideTextHandles(); + DismissTextHandles(); ShowSelectionHandlesAutomatically(); selection_controller_->OnSelectionEditable(true); selection_controller_->OnSelectionEmpty(true); diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h index 063a515f7910f..129b773fbfcd9 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.h +++ b/content/browser/renderer_host/render_widget_host_view_android.h @@ -250,7 +250,8 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid bool HasValidFrame() const; void MoveCaret(const gfx::Point& point); - void HideTextHandles(); + void DismissTextHandles(); + void SetTextHandlesTemporarilyHidden(bool hidden); void OnShowingPastePopup(const gfx::PointF& point); void SynchronousFrameMetadata( diff --git a/content/browser/service_worker/service_worker_cache_listener.cc b/content/browser/service_worker/service_worker_cache_listener.cc index 911517acbbf14..e52c940666d5d 100644 --- a/content/browser/service_worker/service_worker_cache_listener.cc +++ b/content/browser/service_worker/service_worker_cache_listener.cc @@ -417,7 +417,8 @@ void ServiceWorkerCacheListener::OnCachePutCallback( return; } - StoreBlobDataHandle(blob_data_handle.Pass()); + if (blob_data_handle) + StoreBlobDataHandle(blob_data_handle.Pass()); std::vector responses; responses.push_back(*response); @@ -438,6 +439,7 @@ void ServiceWorkerCacheListener::DropCacheReference(CacheID cache_id) { void ServiceWorkerCacheListener::StoreBlobDataHandle( scoped_ptr blob_data_handle) { + DCHECK(blob_data_handle); std::pair rv = blob_handle_store_.insert(std::make_pair( blob_data_handle->uuid(), std::list())); diff --git a/content/browser/ssl/ssl_policy.cc b/content/browser/ssl/ssl_policy.cc index 610f741dd98f6..51ae7b2a1c800 100644 --- a/content/browser/ssl/ssl_policy.cc +++ b/content/browser/ssl/ssl_policy.cc @@ -56,7 +56,6 @@ void SSLPolicy::OnCertError(SSLCertErrorHandler* handler) { case net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM: case net::ERR_CERT_WEAK_KEY: case net::ERR_CERT_NAME_CONSTRAINT_VIOLATION: - case net::ERR_CERT_VALIDITY_TOO_LONG: if (!handler->fatal()) options_mask |= OVERRIDABLE; else diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index d3e8b13b9d3db..860ae180ada27 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc @@ -598,6 +598,10 @@ const GURL& WebContentsImpl::GetLastCommittedURL() const { return entry ? entry->GetVirtualURL() : GURL::EmptyGURL(); } +ScreenOrientationDispatcherHost* WebContentsImpl::GetScreenOrientationDispatcherHost() { + return screen_orientation_dispatcher_host_.get(); +} + WebContentsDelegate* WebContentsImpl::GetDelegate() { return delegate_; } diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index 7869292bdb0c4..fb05fafb6aaea 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h @@ -199,6 +199,7 @@ class CONTENT_EXPORT WebContentsImpl void ClearNavigationTransitionData(); // WebContents ------------------------------------------------------ + ScreenOrientationDispatcherHost* GetScreenOrientationDispatcherHost() override; WebContentsDelegate* GetDelegate() override; void SetDelegate(WebContentsDelegate* delegate) override; NavigationControllerImpl& GetController() override; diff --git a/content/browser/web_contents/web_contents_view_mac.mm b/content/browser/web_contents/web_contents_view_mac.mm index 20c97b8fda21f..3c99ac330ccad 100644 --- a/content/browser/web_contents/web_contents_view_mac.mm +++ b/content/browser/web_contents/web_contents_view_mac.mm @@ -605,6 +605,12 @@ - (void)viewWillMoveToWindow:(NSWindow*)newWindow { // Occlusion notification APIs are new in Mavericks. bool supportsOcclusionAPIs = base::mac::IsOSMavericksOrLater(); + // Use of occlusion APIs is causing bugs: + // http://crbug.com/430968: focus set incorrectly. + // http://crbug.com/431272: flashes of incorrect content. + // http://crbug.com/310374: white flashes (comment 22). + supportsOcclusionAPIs = false; + if (supportsOcclusionAPIs) { if (oldWindow) { [notificationCenter diff --git a/content/child/blink_platform_impl.cc b/content/child/blink_platform_impl.cc index 79f72adcffcbe..144a98314eefc 100644 --- a/content/child/blink_platform_impl.cc +++ b/content/child/blink_platform_impl.cc @@ -786,6 +786,8 @@ const DataResource kDataResources[] = { IDR_MEDIAPLAYER_CAST_BUTTON_ON, ui::SCALE_FACTOR_100P }, { "mediaplayerFullscreenDisabled", IDR_MEDIAPLAYER_FULLSCREEN_BUTTON_DISABLED, ui::SCALE_FACTOR_100P }, + { "mediaplayerOverlayCastOff", + IDR_MEDIAPLAYER_OVERLAY_CAST_BUTTON_OFF, ui::SCALE_FACTOR_100P }, { "mediaplayerOverlayPlay", IDR_MEDIAPLAYER_OVERLAY_PLAY_BUTTON, ui::SCALE_FACTOR_100P }, #if defined(OS_MACOSX) diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index 16519271659ab..ab9f619d42a74 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc @@ -44,8 +44,8 @@ static void SetRuntimeFeatureDefaultsForPlatform() { // Android does not have support for PagePopup WebRuntimeFeatures::enablePagePopup(false); - // Android does not yet support the Web Notification API. crbug.com/115320 - WebRuntimeFeatures::enableNotifications(false); + // Crosswalk supports the Web Notification API on Android. + WebRuntimeFeatures::enableNotifications(true); // Android does not yet support SharedWorker. crbug.com/154571 WebRuntimeFeatures::enableSharedWorker(false); // Android does not yet support NavigatorContentUtils. @@ -77,6 +77,10 @@ static void SetRuntimeFeatureDefaultsForPlatform() { if (base::win::OSInfo::GetInstance()->version() >= base::win::VERSION_WIN8) WebRuntimeFeatures::enableScreenOrientation(false); #endif // OS_WIN + +#if defined(OS_TIZEN) + WebRuntimeFeatures::enableOrientationEvent(true); +#endif // defined(OS_TIZEN) } void SetRuntimeFeaturesDefaultsAndUpdateFromArgs( @@ -114,6 +118,9 @@ void SetRuntimeFeaturesDefaultsAndUpdateFromArgs( if (!command_line.HasSwitch(switches::kEnableSpeechRecognition)) WebRuntimeFeatures::enableScriptedSpeech(false); + if (command_line.HasSwitch(switches::kEnableExperimentalWebPlatformFeatures)) + WebRuntimeFeatures::enableNotifications(true); + // WebAudio is enabled by default on ARM and X86, if the MediaCodec // API is available. WebRuntimeFeatures::enableWebAudio( diff --git a/content/child/web_url_loader_impl.cc b/content/child/web_url_loader_impl.cc index 7249d16229239..b51d799047c42 100644 --- a/content/child/web_url_loader_impl.cc +++ b/content/child/web_url_loader_impl.cc @@ -551,6 +551,9 @@ bool WebURLLoaderImpl::Context::OnReceivedRedirect( new_request.setDownloadToFile(request_.downloadToFile()); new_request.setRequestContext(request_.requestContext()); new_request.setFrameType(request_.frameType()); + new_request.setSkipServiceWorker(request_.skipServiceWorker()); + new_request.setFetchRequestMode(request_.fetchRequestMode()); + new_request.setFetchCredentialsMode(request_.fetchCredentialsMode()); new_request.setHTTPReferrer(WebString::fromUTF8(redirect_info.new_referrer), referrer_policy_); diff --git a/content/common/accessibility_messages.h b/content/common/accessibility_messages.h index fac9830d047f1..69dfb51d3aeab 100644 --- a/content/common/accessibility_messages.h +++ b/content/common/accessibility_messages.h @@ -153,6 +153,13 @@ IPC_MESSAGE_ROUTED2(AccessibilityMsg_SetValue, IPC_MESSAGE_ROUTED1(AccessibilityMsg_HitTest, gfx::Point /* location to test */) +// Relay a request from assistive technology to set accessibility focus +// to a given node. On platforms where this is used (currently Android), +// inline text boxes are only computed for the node with accessibility focus, +// rather than for the whole tree. +IPC_MESSAGE_ROUTED1(AccessibilityMsg_SetAccessibilityFocus, + int /* object id */) + // Tells the render view that a AccessibilityHostMsg_Events // message was processed and it can send addition events. IPC_MESSAGE_ROUTED0(AccessibilityMsg_Events_ACK) diff --git a/content/common/content_message_generator.h b/content/common/content_message_generator.h index c8ec407e65038..a4ce2f94fe7a8 100644 --- a/content/common/content_message_generator.h +++ b/content/common/content_message_generator.h @@ -71,3 +71,7 @@ #include "content/common/gin_java_bridge_messages.h" #include "content/common/media/media_player_messages_android.h" #endif // defined(OS_ANDROID) + +#if defined(OS_TIZEN) && defined(ENABLE_MURPHY) +#include "xwalk/tizen/common/media/media_player_messages.h" +#endif diff --git a/content/common/gpu/image_transport_surface_calayer_mac.h b/content/common/gpu/image_transport_surface_calayer_mac.h index 1de28b3f97dae..1a7c3a211d6a3 100644 --- a/content/common/gpu/image_transport_surface_calayer_mac.h +++ b/content/common/gpu/image_transport_surface_calayer_mac.h @@ -9,6 +9,7 @@ #include "content/common/gpu/image_transport_surface_fbo_mac.h" #include "ui/base/cocoa/remote_layer_api.h" #include "ui/gl/gl_bindings.h" +#include "ui/gl/gpu_switching_observer.h" #include "ui/gl/scoped_cgl.h" @class ImageTransportLayer; @@ -17,7 +18,8 @@ namespace content { // Allocate CAOpenGLLayer-backed storage for an FBO image transport surface. class CALayerStorageProvider - : public ImageTransportSurfaceFBO::StorageProvider { + : public ImageTransportSurfaceFBO::StorageProvider, + public ui::GpuSwitchingObserver { public: CALayerStorageProvider(ImageTransportSurfaceFBO* transport_surface); ~CALayerStorageProvider() override; @@ -40,6 +42,9 @@ class CALayerStorageProvider void LayerDoDraw(); void LayerResetStorageProvider(); + // ui::GpuSwitchingObserver implementation. + void OnGpuSwitched() override; + private: void DrawImmediatelyAndUnblockBrowser(); @@ -76,6 +81,16 @@ class CALayerStorageProvider base::scoped_nsobject context_; base::scoped_nsobject layer_; + // When a CAContext is destroyed in the GPU process, it will become a blank + // CALayer in the browser process. Put retains on these contexts in this queue + // when they are discarded, and remove one item from the queue as each frame + // is acked. + std::list > previously_discarded_contexts_; + + // Indicates that the CALayer should be recreated at the next swap. This is + // to ensure that the CGLContext created for the CALayer be on the right GPU. + bool recreate_layer_after_gpu_switch_; + // Weak factory against which a timeout task for forcing a draw is created. base::WeakPtrFactory pending_draw_weak_factory_; diff --git a/content/common/gpu/image_transport_surface_calayer_mac.mm b/content/common/gpu/image_transport_surface_calayer_mac.mm index 264b97f4a28ed..0147b3c686a6c 100644 --- a/content/common/gpu/image_transport_surface_calayer_mac.mm +++ b/content/common/gpu/image_transport_surface_calayer_mac.mm @@ -13,6 +13,11 @@ #include "ui/gfx/geometry/size_conversions.h" #include "ui/gl/gl_gl_api_implementation.h" #include "ui/gl/gl_switches.h" +#include "ui/gl/gpu_switching_manager.h" + +namespace { +const size_t kFramesToKeepCAContextAfterDiscard = 2; +} @interface ImageTransportLayer : CAOpenGLLayer { content::CALayerStorageProvider* storageProvider_; @@ -97,9 +102,13 @@ - (void)drawInCGLContext:(CGLContextObj)glContext can_draw_returned_false_count_(0), fbo_texture_(0), fbo_scale_factor_(1), - pending_draw_weak_factory_(this) {} + recreate_layer_after_gpu_switch_(false), + pending_draw_weak_factory_(this) { + ui::GpuSwitchingManager::GetInstance()->AddObserver(this); +} CALayerStorageProvider::~CALayerStorageProvider() { + ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this); } gfx::Size CALayerStorageProvider::GetRoundedSize(gfx::Size size) { @@ -155,10 +164,22 @@ - (void)drawInCGLContext:(CGLContextObj)glContext void CALayerStorageProvider::SwapBuffers( const gfx::Size& size, float scale_factor) { DCHECK(!has_pending_draw_); + + // Recreate the CALayer on the new GPU if a GPU switch has occurred. Note + // that the CAContext will retain a reference to the old CALayer until the + // call to -[CAContext setLayer:] replaces the old CALayer with the new one. + if (recreate_layer_after_gpu_switch_) { + [layer_ resetStorageProvider]; + layer_.reset(); + recreate_layer_after_gpu_switch_ = false; + } + + // Set the pending draw flag only after destroying the old layer (otherwise + // destroying it will un-set the flag). has_pending_draw_ = true; // Allocate a CAContext to use to transport the CALayer to the browser - // process. + // process, if needed. if (!context_) { base::scoped_nsobject dict([[NSDictionary alloc] init]); CGSConnectionID connection_id = CGSMainConnectionID(); @@ -167,7 +188,7 @@ - (void)drawInCGLContext:(CGLContextObj)glContext [context_ retain]; } - // Allocate a CALayer to use to draw the content. + // Allocate a CALayer to use to draw the content, if needed. if (!layer_) { layer_.reset([[ImageTransportLayer alloc] initWithStorageProvider:this]); gfx::Size dip_size(gfx::ToFlooredSize(gfx::ScaleSize( @@ -180,6 +201,11 @@ - (void)drawInCGLContext:(CGLContextObj)glContext [context_ setLayer:layer_]; } + // Replacing the CAContext's CALayer will sometimes results in an immediate + // draw. If that happens, early-out. + if (!has_pending_draw_) + return; + // Tell CoreAnimation to draw our frame. if (gpu_vsync_disabled_ || throttling_disabled_) { DrawImmediatelyAndUnblockBrowser(); @@ -228,12 +254,27 @@ - (void)drawInCGLContext:(CGLContextObj)glContext // at the next swap. [layer_ resetStorageProvider]; layer_.reset(); + + // If we remove all references to the CAContext in this process, it will be + // blanked-out in the browser process (even if the browser process is inside + // a NSDisableScreenUpdates block). Ensure that the context is kept around + // until a fixed number of frames (determined empirically) have been acked. + // http://crbug.com/425819 + while (previously_discarded_contexts_.size() < + kFramesToKeepCAContextAfterDiscard) { + previously_discarded_contexts_.push_back( + base::scoped_nsobject()); + } + previously_discarded_contexts_.push_back(context_); + context_.reset(); } void CALayerStorageProvider::SwapBuffersAckedByBrowser( bool disable_throttling) { throttling_disabled_ = disable_throttling; + if (!previously_discarded_contexts_.empty()) + previously_discarded_contexts_.pop_front(); } CGLContextObj CALayerStorageProvider::LayerShareGroupContext() { @@ -312,6 +353,10 @@ - (void)drawInCGLContext:(CGLContextObj)glContext UnblockBrowserIfNeeded(); } +void CALayerStorageProvider::OnGpuSwitched() { + recreate_layer_after_gpu_switch_ = true; +} + void CALayerStorageProvider::UnblockBrowserIfNeeded() { if (!has_pending_draw_) return; diff --git a/content/common/gpu/media/dxva_video_decode_accelerator.cc b/content/common/gpu/media/dxva_video_decode_accelerator.cc index c5cc291c02610..530358e155f6c 100644 --- a/content/common/gpu/media/dxva_video_decode_accelerator.cc +++ b/content/common/gpu/media/dxva_video_decode_accelerator.cc @@ -323,7 +323,7 @@ bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer:: glBindTexture(GL_TEXTURE_2D, picture_buffer_.texture_id()); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); base::win::ScopedComPtr d3d_surface; hr = decoding_texture_->GetSurfaceLevel(0, d3d_surface.Receive()); @@ -362,7 +362,7 @@ bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer:: egl_display, decoding_surface_, EGL_BACK_BUFFER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, current_texture); return true; } diff --git a/content/common/sandbox_linux/bpf_gpu_policy_linux.cc b/content/common/sandbox_linux/bpf_gpu_policy_linux.cc index e1a33d02a9b9f..37e3a83336a37 100644 --- a/content/common/sandbox_linux/bpf_gpu_policy_linux.cc +++ b/content/common/sandbox_linux/bpf_gpu_policy_linux.cc @@ -240,11 +240,19 @@ bool GpuProcessPolicy::PreSandboxHook() { if (IsAcceleratedVideoEnabled()) { const char* I965DrvVideoPath = NULL; +#if defined(OS_TIZEN) + if (IsArchitectureX86_64()) { + I965DrvVideoPath = "/usr/lib64/dri/i965_dri.so"; + } else if (IsArchitectureI386()) { + I965DrvVideoPath = "/usr/lib/dri/i965_dri.so"; + } +#else if (IsArchitectureX86_64()) { I965DrvVideoPath = "/usr/lib64/va/drivers/i965_drv_video.so"; } else if (IsArchitectureI386()) { I965DrvVideoPath = "/usr/lib/va/drivers/i965_drv_video.so"; } +#endif dlopen(I965DrvVideoPath, RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE); dlopen("libva.so.1", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE); diff --git a/content/common/set_process_title.cc b/content/common/set_process_title.cc index fdbf06cd0d8a9..fa7e7a39014c2 100644 --- a/content/common/set_process_title.cc +++ b/content/common/set_process_title.cc @@ -89,4 +89,10 @@ void SetProcessTitleFromCommandLine(const char** /* main_argv */) { #endif +#if defined(OS_TIZEN_MOBILE) +void StoreArgvPointerAddress(const char** main_argv) { + setproctitle_init(main_argv); +} +#endif + } // namespace content diff --git a/content/common/set_process_title.h b/content/common/set_process_title.h index 91ea61a89a1a5..d53c6ef09d831 100644 --- a/content/common/set_process_title.h +++ b/content/common/set_process_title.h @@ -22,6 +22,10 @@ namespace content { // will try to fix it so the "effective" command line shows up instead. void SetProcessTitleFromCommandLine(const char** main_argv); +#if defined(OS_TIZEN_MOBILE) +void StoreArgvPointerAddress(const char** main_argv); +#endif + } // namespace content #endif // CONTENT_COMMON_SET_PROCESS_TITLE_H_ diff --git a/content/content_browser.gypi b/content/content_browser.gypi index 2cf449d3fe8ea..0af4aec5b1c13 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -1858,6 +1858,26 @@ 'browser/power_save_blocker_x11.cc', ], }], + ['tizen==1 and enable_murphy==1', { + 'sources': [ + '<(DEPTH)/xwalk/tizen/browser/media/browser_mediaplayer_manager.cc', + '<(DEPTH)/xwalk/tizen/browser/media/browser_mediaplayer_manager.h', + '<(DEPTH)/xwalk/tizen/browser/media/media_webcontents_observer.cc', + '<(DEPTH)/xwalk/tizen/browser/media/media_webcontents_observer.h', + '<(DEPTH)/xwalk/tizen/browser/media/murphy_mainloop.cc', + '<(DEPTH)/xwalk/tizen/browser/media/murphy_mainloop.h', + '<(DEPTH)/xwalk/tizen/browser/media/murphy_resource.cc', + '<(DEPTH)/xwalk/tizen/browser/media/murphy_resource.h', + '<(DEPTH)/xwalk/tizen/browser/media/murphy_resource_manager.cc', + '<(DEPTH)/xwalk/tizen/browser/media/murphy_resource_manager.h', + ], + 'dependencies': [ + '../build/linux/system.gyp:resource_manager', + ], + 'export_dependent_settings': [ + '../build/linux/system.gyp:resource_manager', + ], + }], ['os_bsd==1', { 'sources/': [ ['exclude', '^browser/gamepad/gamepad_platform_data_fetcher_linux\\.cc$'], diff --git a/content/content_common.gypi b/content/content_common.gypi index 6d9a28d149347..dac68f7637036 100644 --- a/content/content_common.gypi +++ b/content/content_common.gypi @@ -862,6 +862,11 @@ '<(DEPTH)/third_party/khronos', ], }], + ['tizen==1 and enable_murphy==1', { + 'sources': [ + '<(DEPTH)/xwalk/tizen/common/media/media_player_messages.h', + ], + }], ['OS=="win" and directxsdk_exists=="True"', { 'actions': [ { diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi index 144f8de37efd4..76aab96c3f146 100644 --- a/content/content_renderer.gypi +++ b/content/content_renderer.gypi @@ -853,6 +853,14 @@ 'renderer/media/crypto/renderer_cdm_manager.h', ], }], + ['tizen==1 and enable_murphy==1', { + 'sources': [ + '<(DEPTH)/xwalk/tizen/renderer/media/mediaplayer_impl.cc', + '<(DEPTH)/xwalk/tizen/renderer/media/mediaplayer_impl.h', + '<(DEPTH)/xwalk/tizen/renderer/media/renderer_mediaplayer_manager.cc', + '<(DEPTH)/xwalk/tizen/renderer/media/renderer_mediaplayer_manager.h', + ], + }], ], 'target_conditions': [ ['OS=="android"', { diff --git a/content/content_tests.gypi b/content/content_tests.gypi index d48ac719da234..ceb8a35b7c2f1 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi @@ -854,21 +854,6 @@ '../third_party/webrtc/modules/modules.gyp:desktop_capture', ], }], - ['enable_webrtc==1 and OS=="mac"', { - 'variables': { - 'libpeer_target_type%': 'static_library', - }, - 'conditions': [ - ['libpeer_target_type!="static_library"', { - 'copies': [{ - 'destination': '<(PRODUCT_DIR)/Libraries', - 'files': [ - '<(PRODUCT_DIR)/libpeerconnection.so', - ], - }], - }], - ], - }], ['enable_webrtc==1 and chromeos==1', { 'sources': [ 'browser/media/capture/desktop_capture_device_aura_unittest.cc', diff --git a/content/content_unittests.isolate b/content/content_unittests.isolate index 72d8d3df13b7f..bc982e2c3dd92 100644 --- a/content/content_unittests.isolate +++ b/content/content_unittests.isolate @@ -58,13 +58,6 @@ ], }, }], - ['OS=="linux" and libpeer_target_type=="loadable_module"', { - 'variables': { - 'files': [ - '<(PRODUCT_DIR)/lib/libpeerconnection.so', - ], - }, - }], ['OS=="mac"', { 'variables': { 'command': [ @@ -104,13 +97,6 @@ ], }, }], - ['OS=="win" and libpeer_target_type=="loadable_module"', { - 'variables': { - 'files': [ - '<(PRODUCT_DIR)/libpeerconnection.dll', - ], - }, - }], ], 'includes': [ '../base/base.isolate', diff --git a/content/public/android/java/res/menu/select_action_menu.xml b/content/public/android/java/res/menu/select_action_menu.xml index 65c729acee220..37932603d3744 100644 --- a/content/public/android/java/res/menu/select_action_menu.xml +++ b/content/public/android/java/res/menu/select_action_menu.xml @@ -37,14 +37,14 @@ /> diff --git a/content/public/android/java/res/values-v17/styles.xml b/content/public/android/java/res/values-v17/styles.xml index 7c439dc860279..dbdc8b1d3b19a 100644 --- a/content/public/android/java/res/values-v17/styles.xml +++ b/content/public/android/java/res/values-v17/styles.xml @@ -10,4 +10,10 @@ @android:layout/select_dialog_singlechoice @android:layout/select_dialog_multichoice + + diff --git a/content/public/android/java/res/values-v21/styles.xml b/content/public/android/java/res/values-v21/styles.xml new file mode 100644 index 0000000000000..a01b0c70d5803 --- /dev/null +++ b/content/public/android/java/res/values-v21/styles.xml @@ -0,0 +1,14 @@ + + + + + + + diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java index 7d34565c4c993..8e4645f648db4 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java +++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java @@ -618,7 +618,7 @@ private ImeAdapter createImeAdapter(Context context) { public void onImeEvent() { mPopupZoomer.hide(true); getContentViewClient().onImeEvent(); - if (mFocusedNodeEditable) hideTextHandles(); + if (mFocusedNodeEditable) dismissTextHandles(); } @Override @@ -700,6 +700,7 @@ public void initialize(ViewGroup containerView, InternalAccessDelegate internalD mRenderCoordinates.reset(); initPopupZoomer(mContext); mImeAdapter = createImeAdapter(mContext); + attachImeAdapter(); mAccessibilityInjector = AccessibilityInjector.newInstance(this); @@ -1319,6 +1320,10 @@ public ContentSettings getContentSettings() { private void hidePopupsAndClearSelection() { mUnselectAllOnActionModeDismiss = true; hidePopups(); + // Clear the selection. The selection is cleared on destroying IME + // and also here since we may receive destroy first, for example + // when focus is lost in webview. + clearUserSelection(); } private void hidePopupsAndPreserveSelection() { @@ -1326,12 +1331,23 @@ private void hidePopupsAndPreserveSelection() { hidePopups(); } + private void clearUserSelection() { + if (mFocusedNodeEditable) { + if (mInputConnection != null) { + int selectionEnd = Selection.getSelectionEnd(mEditable); + mInputConnection.setSelection(selectionEnd, selectionEnd); + } + } else if (mImeAdapter != null) { + mImeAdapter.unselect(); + } + } + private void hidePopups() { hideSelectActionBar(); hidePastePopup(); hideSelectPopup(); mPopupZoomer.hide(false); - if (mUnselectAllOnActionModeDismiss) hideTextHandles(); + if (mUnselectAllOnActionModeDismiss) dismissTextHandles(); } private void restoreSelectionPopupsIfNecessary() { @@ -1360,6 +1376,7 @@ private void resetGestureDetection() { @SuppressWarnings("javadoc") public void onAttachedToWindow() { setAccessibilityState(mAccessibilityManager.isEnabled()); + setTextHandlesTemporarilyHidden(false); restoreSelectionPopupsIfNecessary(); ScreenOrientationListener.getInstance().addObserver(this, mContext); GamepadList.onAttachedToWindow(mContext); @@ -1372,12 +1389,19 @@ public void onAttachedToWindow() { @SuppressLint("MissingSuperCall") public void onDetachedFromWindow() { setInjectedAccessibility(false); - hidePopupsAndPreserveSelection(); mZoomControlsDelegate.dismissZoomPicker(); unregisterAccessibilityContentObserver(); ScreenOrientationListener.getInstance().removeObserver(this); GamepadList.onDetachedFromWindow(); + + // WebView uses PopupWindows for handle rendering, which may remain + // unintentionally visible even after the WebView has been detached. + // Override the handle visibility explicitly to address this, but + // preserve the underlying selection for detachment cases like screen + // locking and app switching. + setTextHandlesTemporarilyHidden(true); + hidePopupsAndPreserveSelection(); } /** @@ -1930,13 +1954,8 @@ public boolean isSelectionEditable() { public void onDestroyActionMode() { mActionMode = null; if (mUnselectAllOnActionModeDismiss) { - hideTextHandles(); - if (isSelectionEditable()) { - int selectionEnd = Selection.getSelectionEnd(mEditable); - mInputConnection.setSelection(selectionEnd, selectionEnd); - } else { - mImeAdapter.unselect(); - } + dismissTextHandles(); + clearUserSelection(); } getContentViewClient().onContextualActionBarHidden(); } @@ -2074,10 +2093,15 @@ private void onSelectionEvent(int eventType, float posXDip, float posYDip) { getContentViewClient().onSelectionEvent(eventType, posXDip * scale, posYDip * scale); } - private void hideTextHandles() { + private void dismissTextHandles() { mHasSelection = false; mHasInsertion = false; - if (mNativeContentViewCore != 0) nativeHideTextHandles(mNativeContentViewCore); + if (mNativeContentViewCore != 0) nativeDismissTextHandles(mNativeContentViewCore); + } + + private void setTextHandlesTemporarilyHidden(boolean hide) { + if (mNativeContentViewCore == 0) return; + nativeSetTextHandlesTemporarilyHidden(mNativeContentViewCore, hide); } /** @@ -2227,7 +2251,7 @@ private void showSelectPopup(long nativeSelectPopupSourceFrame, Rect bounds, Str for (int i = 0; i < items.length; i++) { popupItems.add(new SelectPopupItem(items[i], enabled[i])); } - if (DeviceFormFactor.isTablet(mContext) && !multiple) { + if (DeviceFormFactor.isTablet(mContext) && !multiple && !isTouchExplorationEnabled()) { mSelectPopup = new SelectPopupDropdown(this, popupItems, bounds, selectedIndices); } else { mSelectPopup = new SelectPopupDialog(this, popupItems, multiple, selectedIndices); @@ -2327,7 +2351,7 @@ private PastePopupMenu getPastePopup() { @Override public void paste() { mImeAdapter.paste(); - hideTextHandles(); + dismissTextHandles(); } }); } @@ -3001,7 +3025,9 @@ private native void nativeSelectBetweenCoordinates( private native void nativeMoveCaret(long nativeContentViewCoreImpl, float x, float y); - private native void nativeHideTextHandles(long nativeContentViewCoreImpl); + private native void nativeDismissTextHandles(long nativeContentViewCoreImpl); + private native void nativeSetTextHandlesTemporarilyHidden( + long nativeContentViewCoreImpl, boolean hidden); private native void nativeResetGestureDetection(long nativeContentViewCoreImpl); diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java index a3093989bc9ae..4ef5103e416c5 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java +++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java @@ -7,9 +7,12 @@ import android.content.Context; import android.graphics.Color; import android.graphics.PixelFormat; +import android.graphics.SurfaceTexture; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; +import android.view.TextureView; +import android.view.TextureView.SurfaceTextureListener; import android.widget.FrameLayout; import org.chromium.base.CalledByNative; @@ -31,7 +34,100 @@ public class ContentViewRenderView extends FrameLayout { private final SurfaceView mSurfaceView; protected ContentViewCore mContentViewCore; + // Enum for the type of compositing surface: + // SURFACE_VIEW - Use SurfaceView as compositing surface which + // has a bit performance advantage + // TEXTURE_VIEW - Use TextureView as compositing surface which + // supports animation on the View + public enum CompositingSurfaceType { SURFACE_VIEW, TEXTURE_VIEW }; + + // The stuff for TextureView usage. It is not a good practice to mix 2 different + // implementations into one single class. However, for the sake of reducing the + // effort of rebasing maintanence in future, here we avoid heavily changes in + // this class. + private TextureView mTextureView; + private Surface mSurface; + private CompositingSurfaceType mCompositingSurfaceType; + private ContentReadbackHandler mContentReadbackHandler; + // The listener which will be triggered when below two conditions become valid. + // 1. The view has been initialized and ready to draw content to the screen. + // 2. The compositor finished compositing and the OpenGL buffers has been swapped. + // Which means the view has been updated with visually non-empty content. + // This listener will be triggered only once after registered. + private FirstRenderedFrameListener mFirstRenderedFrameListener; + private boolean mFirstFrameReceived; + + public interface FirstRenderedFrameListener{ + public void onFirstFrameReceived(); + } + + // Initialize the TextureView for rendering ContentView and configure the callback + // listeners. + private void initTextureView(Context context) { + mTextureView = new TextureView(context); + mTextureView.setBackgroundColor(Color.WHITE); + + mTextureView.setSurfaceTextureListener(new SurfaceTextureListener() { + @Override + public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, + int width, int height) { + assert mNativeContentViewRenderView != 0; + + mSurface = new Surface(surfaceTexture); + nativeSurfaceCreated(mNativeContentViewRenderView); + // Force to trigger the compositor to start working. + onSurfaceTextureSizeChanged(surfaceTexture, width, height); + onReadyToRender(); + } + + @Override + public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, + int width, int height) { + assert mNativeContentViewRenderView != 0 && mSurface != null; + assert surfaceTexture == mTextureView.getSurfaceTexture(); + assert mSurface != null; + + // Here we hard-code the pixel format since the native part requires + // the format parameter to decide if the compositing surface should be + // replaced with a new one when the format is changed. + // + // If TextureView is used, the surface won't be possible to changed, + // so that the format is also not changed. There is no special reason + // to use RGBA_8888 value since the native part won't use its real + // value to do something for drawing. + // + // TODO(hmin): Figure out how to get pixel format from SurfaceTexture. + int format = PixelFormat.RGBA_8888; + nativeSurfaceChanged(mNativeContentViewRenderView, + format, width, height, mSurface); + if (mContentViewCore != null) { + mContentViewCore.onPhysicalBackingSizeChanged( + width, height); + } + } + + @Override + public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { + assert mNativeContentViewRenderView != 0; + nativeSurfaceDestroyed(mNativeContentViewRenderView); + + // Release the underlying surface to make it invalid. + mSurface.release(); + mSurface = null; + return true; + } + + @Override + public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { + // Do nothing since the SurfaceTexture won't be updated via updateTexImage(). + } + }); + } + + public ContentViewRenderView(Context context) { + this(context, CompositingSurfaceType.SURFACE_VIEW); + } /** * Constructs a new ContentViewRenderView. @@ -39,10 +135,27 @@ public class ContentViewRenderView extends FrameLayout { * hierarchy before the first draw to avoid a black flash that is seen every time a * {@link SurfaceView} is added. * @param context The context used to create this. + * @param surfaceType TextureView is used as compositing target surface, + * otherwise SurfaceView is used. */ - public ContentViewRenderView(Context context) { + public ContentViewRenderView(Context context, CompositingSurfaceType surfaceType) { super(context); + mCompositingSurfaceType = surfaceType; + if (surfaceType == CompositingSurfaceType.TEXTURE_VIEW) { + initTextureView(context); + + addView(mTextureView, + new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.MATCH_PARENT)); + + // Avoid compiler warning. + mSurfaceView = null; + mSurfaceCallback = null; + return; + } + mSurfaceView = createSurfaceView(getContext()); mSurfaceView.setZOrderMediaOverlay(true); @@ -60,11 +173,23 @@ public ContentViewRenderView(Context context) { * @param rootWindow The {@link WindowAndroid} this render view should be linked to. */ public void onNativeLibraryLoaded(WindowAndroid rootWindow) { - assert !mSurfaceView.getHolder().getSurface().isValid() : - "Surface created before native library loaded."; assert rootWindow != null; mNativeContentViewRenderView = nativeInit(rootWindow.getNativePointer()); assert mNativeContentViewRenderView != 0; + + mContentReadbackHandler = new ContentReadbackHandler() { + @Override + protected boolean readyForReadback() { + return mNativeContentViewRenderView != 0 && mContentViewCore != null; + } + }; + mContentReadbackHandler.initNativeContentReadbackHandler(); + + if (mCompositingSurfaceType == CompositingSurfaceType.TEXTURE_VIEW) + return; + + assert !mSurfaceView.getHolder().getSurface().isValid() : + "Surface created before native library loaded."; mSurfaceCallback = new SurfaceHolder.Callback() { @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { @@ -93,14 +218,6 @@ public void surfaceDestroyed(SurfaceHolder holder) { }; mSurfaceView.getHolder().addCallback(mSurfaceCallback); mSurfaceView.setVisibility(VISIBLE); - - mContentReadbackHandler = new ContentReadbackHandler() { - @Override - protected boolean readyForReadback() { - return mNativeContentViewRenderView != 0 && mContentViewCore != null; - } - }; - mContentReadbackHandler.initNativeContentReadbackHandler(); } /** @@ -129,7 +246,15 @@ public void setSurfaceViewBackgroundColor(int color) { public void destroy() { mContentReadbackHandler.destroy(); mContentReadbackHandler = null; - mSurfaceView.getHolder().removeCallback(mSurfaceCallback); + if (mCompositingSurfaceType == CompositingSurfaceType.TEXTURE_VIEW) { + mTextureView.setSurfaceTextureListener(null); + if (mSurface != null) { + mSurface.release(); + mSurface = null; + } + } else { + mSurfaceView.getHolder().removeCallback(mSurfaceCallback); + } nativeDestroy(mNativeContentViewRenderView); mNativeContentViewRenderView = 0; } @@ -173,11 +298,18 @@ protected SurfaceView createSurfaceView(Context context) { return new SurfaceView(context); } + public void registerFirstRenderedFrameListener(FirstRenderedFrameListener listener) { + mFirstRenderedFrameListener = listener; + if (mFirstFrameReceived && mFirstRenderedFrameListener != null) { + mFirstRenderedFrameListener.onFirstFrameReceived(); + } + } + /** * @return whether the surface view is initialized and ready to render. */ public boolean isInitialized() { - return mSurfaceView.getHolder().getSurface() != null; + return mSurfaceView.getHolder().getSurface() != null || mSurface != null; } /** @@ -185,6 +317,10 @@ public boolean isInitialized() { * @param enabled Whether overlay mode is enabled. */ public void setOverlayVideoMode(boolean enabled) { + if (mCompositingSurfaceType == CompositingSurfaceType.TEXTURE_VIEW) { + nativeSetOverlayVideoMode(mNativeContentViewRenderView, enabled); + return; + } int format = enabled ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE; mSurfaceView.getHolder().setFormat(format); nativeSetOverlayVideoMode(mNativeContentViewRenderView, enabled); @@ -204,6 +340,16 @@ protected void onCompositorLayout() { @CalledByNative private void onSwapBuffersCompleted() { + if (!mFirstFrameReceived && mContentViewCore != null && mContentViewCore.getWebContents().isReady()) { + mFirstFrameReceived = true; + if (mFirstRenderedFrameListener != null) { + mFirstRenderedFrameListener.onFirstFrameReceived(); + } + } + + // Ignore if TextureView is used. + if (mCompositingSurfaceType == CompositingSurfaceType.TEXTURE_VIEW) return; + if (mSurfaceView.getBackground() != null) { post(new Runnable() { @Override public void run() { diff --git a/content/public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java b/content/public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java index de414e2ad8f61..aa2c43aa4dcea 100644 --- a/content/public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java +++ b/content/public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java @@ -225,7 +225,7 @@ boolean configure(Context context, String url, String cookies, String userAgent) return false; } String scheme = uri.getScheme(); - if (scheme == null || scheme.equals("file")) { + if (scheme == null || scheme.equals("file") || scheme.equals("app")) { File file = uriToFile(uri.getPath()); if (!file.exists()) { Log.e(TAG, "File does not exist."); diff --git a/content/public/android/java/src/org/chromium/content/browser/SelectActionModeCallback.java b/content/public/android/java/src/org/chromium/content/browser/SelectActionModeCallback.java index 3035251f45413..25459fbc1cd5f 100644 --- a/content/public/android/java/src/org/chromium/content/browser/SelectActionModeCallback.java +++ b/content/public/android/java/src/org/chromium/content/browser/SelectActionModeCallback.java @@ -121,6 +121,7 @@ public boolean onPrepareActionMode(ActionMode mode, Menu menu) { private void createActionMenu(ActionMode mode, Menu menu) { mode.getMenuInflater().inflate(R.menu.select_action_menu, menu); + if (!mEditable || !canPaste()) { menu.removeItem(R.id.select_action_menu_paste); } diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java index 81cf59584cb4d..cc5367681bbbd 100644 --- a/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java +++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java @@ -8,6 +8,7 @@ import android.graphics.Rect; import android.os.Build; import android.os.Bundle; +import android.provider.Settings; import android.text.SpannableString; import android.text.style.URLSpan; import android.view.MotionEvent; @@ -62,6 +63,7 @@ public class BrowserAccessibilityManager { private int mSelectionGranularity; private int mSelectionStartIndex; private int mSelectionEndIndex; + private boolean mVisible = true; /** * Create a BrowserAccessibilityManager object, which is owned by the C++ @@ -119,6 +121,21 @@ public AccessibilityNodeProvider getAccessibilityNodeProvider() { return null; } + /** + * Set whether the web content made accessible by this class is currently visible. + * Set it to false if the web view is still on the screen but it's obscured by a + * dialog or overlay. This will make every virtual view in the web hierarchy report + * that it's not visible, and not accessibility focusable. + * + * @param visible Whether the web content is currently visible and not obscured. + */ + public void setVisible(boolean visible) { + if (visible == mVisible) return; + + mVisible = visible; + mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); + } + /** * @see AccessibilityNodeProvider#createAccessibilityNodeInfo(int) */ @@ -229,6 +246,7 @@ protected boolean performAction(int virtualViewId, int action, Bundle arguments) return jumpToElementType(elementType, false); } case ACTION_SET_TEXT: { + if (!nativeIsEditableText(mNativeObj, virtualViewId)) return false; if (arguments == null) return false; String newText = arguments.getString( ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE); @@ -236,9 +254,10 @@ protected boolean performAction(int virtualViewId, int action, Bundle arguments) nativeSetTextFieldValue(mNativeObj, virtualViewId, newText); // Match Android framework and set the cursor to the end of the text field. nativeSetSelection(mNativeObj, virtualViewId, newText.length(), newText.length()); - break; + return true; } case AccessibilityNodeInfo.ACTION_SET_SELECTION: { + if (!nativeIsEditableText(mNativeObj, virtualViewId)) return false; int selectionStart = 0; int selectionEnd = 0; if (arguments != null) { @@ -248,7 +267,7 @@ protected boolean performAction(int virtualViewId, int action, Bundle arguments) AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT); } nativeSetSelection(mNativeObj, virtualViewId, selectionStart, selectionEnd); - break; + return true; } case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { if (arguments == null) return false; @@ -272,6 +291,10 @@ protected boolean performAction(int virtualViewId, int action, Bundle arguments) } return previousAtGranularity(granularity, extend); } + case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: + return nativeAdjustSlider(mNativeObj, virtualViewId, true); + case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: + return nativeAdjustSlider(mNativeObj, virtualViewId, false); default: break; } @@ -430,6 +453,16 @@ private boolean moveAccessibilityFocusToId(int newAccessibilityFocusId) { mSelectionGranularity = 0; mSelectionStartIndex = 0; mSelectionEndIndex = 0; + + // Calling nativeSetAccessibilityFocus will asynchronously load inline text boxes for + // this node and its subtree. If accessibility focus is on anything other than + // the root, do it - otherwise set it to -1 so we don't load inline text boxes + // for the whole subtree of the root. + if (mAccessibilityFocusId == mCurrentRootId) + nativeSetAccessibilityFocus(mNativeObj, -1); + else + nativeSetAccessibilityFocus(mNativeObj, mAccessibilityFocusId); + sendAccessibilityEvent(mAccessibilityFocusId, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); return true; @@ -517,7 +550,7 @@ private AccessibilityNodeInfo createNodeForHost(int rootId) { } // Populate the minimum required fields. - result.setVisibleToUser(source.isVisibleToUser()); + result.setVisibleToUser(source.isVisibleToUser() && mVisible); result.setEnabled(source.isEnabled()); result.setPackageName(source.getPackageName()); result.setClassName(source.getClassName()); @@ -573,6 +606,11 @@ private void handleEditableTextChanged(int id) { sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED); } + @CalledByNative + private void handleSliderChanged(int id) { + sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_SCROLLED); + } + @CalledByNative private void handleContentChanged(int id) { int rootId = nativeGetRootId(mNativeObj); @@ -630,9 +668,10 @@ private void addAccessibilityNodeInfoChild(AccessibilityNodeInfo node, int child @CalledByNative private void setAccessibilityNodeInfoBooleanAttributes(AccessibilityNodeInfo node, - int virtualViewId, boolean checkable, boolean checked, boolean clickable, - boolean editableText, boolean enabled, boolean focusable, boolean focused, - boolean password, boolean scrollable, boolean selected, boolean visibleToUser) { + int virtualViewId, boolean canScrollForward, boolean canScrollBackward, + boolean checkable, boolean checked, boolean clickable, boolean editableText, + boolean enabled, boolean focusable, boolean focused, boolean password, + boolean scrollable, boolean selected, boolean visibleToUser) { node.setCheckable(checkable); node.setChecked(checked); node.setClickable(clickable); @@ -642,7 +681,7 @@ private void setAccessibilityNodeInfoBooleanAttributes(AccessibilityNodeInfo nod node.setPassword(password); node.setScrollable(scrollable); node.setSelected(selected); - node.setVisibleToUser(visibleToUser); + node.setVisibleToUser(visibleToUser && mVisible); node.addAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT); node.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT); @@ -658,6 +697,14 @@ private void setAccessibilityNodeInfoBooleanAttributes(AccessibilityNodeInfo nod node.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); } + if (canScrollForward) { + node.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); + } + + if (canScrollBackward) { + node.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); + } + if (focusable) { if (focused) { node.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); @@ -669,7 +716,7 @@ private void setAccessibilityNodeInfoBooleanAttributes(AccessibilityNodeInfo nod if (mAccessibilityFocusId == virtualViewId) { node.setAccessibilityFocused(true); node.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); - } else { + } else if (mVisible) { node.setAccessibilityFocused(false); node.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); } @@ -821,9 +868,9 @@ private void setAccessibilityEventTextChangedAttrs(AccessibilityEvent event, @CalledByNative private void setAccessibilityEventSelectionAttrs(AccessibilityEvent event, - int fromIndex, int addedCount, int itemCount, String text) { + int fromIndex, int toIndex, int itemCount, String text) { event.setFromIndex(fromIndex); - event.setAddedCount(addedCount); + event.setToIndex(toIndex); event.setItemCount(itemCount); event.getText().add(text); } @@ -886,6 +933,13 @@ protected void setAccessibilityEventRangeInfo(AccessibilityEvent event, bundle.putFloat("AccessibilityNodeInfo.RangeInfo.current", current); } + @CalledByNative + boolean shouldExposePasswordText() { + return (Settings.Secure.getInt( + mContentViewCore.getContext().getContentResolver(), + Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0) == 1); + } + private native int nativeGetRootId(long nativeBrowserAccessibilityManagerAndroid); private native boolean nativeIsNodeValid(long nativeBrowserAccessibilityManagerAndroid, int id); private native boolean nativeIsEditableText( @@ -916,4 +970,8 @@ private native boolean nativeNextAtGranularity(long nativeBrowserAccessibilityMa private native boolean nativePreviousAtGranularity( long nativeBrowserAccessibilityManagerAndroid, int selectionGranularity, boolean extendSelection, int id, int cursorIndex); + private native boolean nativeAdjustSlider( + long nativeBrowserAccessibilityManagerAndroid, int id, boolean increment); + private native void nativeSetAccessibilityFocus( + long nativeBrowserAccessibilityManagerAndroid, int id); } diff --git a/content/public/android/java/src/org/chromium/content/browser/input/PopupTouchHandleDrawable.java b/content/public/android/java/src/org/chromium/content/browser/input/PopupTouchHandleDrawable.java index b9542e98d630d..03cc014b6a2cd 100644 --- a/content/public/android/java/src/org/chromium/content/browser/input/PopupTouchHandleDrawable.java +++ b/content/public/android/java/src/org/chromium/content/browser/input/PopupTouchHandleDrawable.java @@ -224,6 +224,7 @@ private void temporarilyHide() { } private void doInvalidate() { + if (!mContainer.isShowing()) return; updatePosition(); updateVisibility(); invalidate(); diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java index 6745a4085c73a..768f4c63931f5 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java @@ -172,15 +172,27 @@ public void run() { @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) public void testRemovalNotReflectedUntilReload() throws Throwable { - injectObjectAndReload(new Object(), "testObject"); + injectObjectAndReload(new Object() { + public void method() { + mTestController.setStringValue("I'm here"); + } + }, "testObject"); assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject")); + executeJavaScript("testObject.method()"); + assertEquals("I'm here", mTestController.waitForStringValue()); runTestOnUiThread(new Runnable() { @Override public void run() { getContentViewCore().removeJavascriptInterface("testObject"); } }); + // Check that the Java object is being held by the Java bridge, thus it's not + // collected. Note that despite that what JavaDoc says about invoking "gc()", both Dalvik + // and ART actually run the collector if called via Runtime. + Runtime.getRuntime().gc(); assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject")); + executeJavaScript("testObject.method()"); + assertEquals("I'm here", mTestController.waitForStringValue()); synchronousPageReload(); assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject")); } diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h index 5478a378158c5..151b54aa2b47a 100644 --- a/content/public/browser/web_contents.h +++ b/content/public/browser/web_contents.h @@ -53,6 +53,7 @@ class RenderFrameHost; class RenderProcessHost; class RenderViewHost; class RenderWidgetHostView; +class ScreenOrientationDispatcherHost; class SiteInstance; class WebContentsDelegate; struct CustomContextMenuContext; @@ -148,6 +149,8 @@ class WebContents : public PageNavigator, // Intrinsic tab state ------------------------------------------------------- + virtual ScreenOrientationDispatcherHost* GetScreenOrientationDispatcherHost() = 0; + // Gets/Sets the delegate. virtual WebContentsDelegate* GetDelegate() = 0; virtual void SetDelegate(WebContentsDelegate* delegate) = 0; diff --git a/content/renderer/accessibility/blink_ax_tree_source.cc b/content/renderer/accessibility/blink_ax_tree_source.cc index a9309826211bd..22c66acbdaa4f 100644 --- a/content/renderer/accessibility/blink_ax_tree_source.cc +++ b/content/renderer/accessibility/blink_ax_tree_source.cc @@ -108,7 +108,8 @@ void AddIntListAttributeFromWebObjects(ui::AXIntListAttribute attr, BlinkAXTreeSource::BlinkAXTreeSource(RenderFrameImpl* render_frame) : render_frame_(render_frame), node_to_frame_routing_id_map_(NULL), - node_to_browser_plugin_instance_id_map_(NULL) { + node_to_browser_plugin_instance_id_map_(NULL), + accessibility_focus_id_(-1) { } BlinkAXTreeSource::~BlinkAXTreeSource() { @@ -147,6 +148,17 @@ int32 BlinkAXTreeSource::GetId(blink::WebAXObject node) const { void BlinkAXTreeSource::GetChildren( blink::WebAXObject parent, std::vector* out_children) const { + if (parent.role() == blink::WebAXRoleStaticText) { + blink::WebAXObject ancestor = parent; + while (!ancestor.isDetached()) { + if (ancestor.axID() == accessibility_focus_id_) { + parent.loadInlineTextBoxes(); + break; + } + ancestor = ancestor.parentObject(); + } + } + bool is_iframe = false; WebNode node = parent.node(); if (!node.isNull() && node.isElementNode()) { diff --git a/content/renderer/accessibility/blink_ax_tree_source.h b/content/renderer/accessibility/blink_ax_tree_source.h index fe338b9895a0f..b08108b12e576 100644 --- a/content/renderer/accessibility/blink_ax_tree_source.h +++ b/content/renderer/accessibility/blink_ax_tree_source.h @@ -29,6 +29,12 @@ class BlinkAXTreeSource // Walks up the ancestor chain to see if this is a descendant of the root. bool IsInTree(blink::WebAXObject node) const; + // Set the id of the node with accessibility focus. The node with + // accessibility focus will force loading inline text box children, + // which aren't always loaded by default on all platforms. + int accessibility_focus_id() { return accessibility_focus_id_; } + void set_accessiblity_focus_id(int id) { accessibility_focus_id_ = id; } + // AXTreeSource implementation. blink::WebAXObject GetRoot() const override; blink::WebAXObject GetFromId(int32 id) const override; @@ -50,6 +56,7 @@ class BlinkAXTreeSource RenderFrameImpl* render_frame_; std::map* node_to_frame_routing_id_map_; std::map* node_to_browser_plugin_instance_id_map_; + int accessibility_focus_id_; }; } // namespace content diff --git a/content/renderer/accessibility/renderer_accessibility.cc b/content/renderer/accessibility/renderer_accessibility.cc index 707f193273b46..ac83a7679972b 100644 --- a/content/renderer/accessibility/renderer_accessibility.cc +++ b/content/renderer/accessibility/renderer_accessibility.cc @@ -43,9 +43,15 @@ RendererAccessibility::RendererAccessibility(RenderFrameImpl* render_frame) WebSettings* settings = web_view->settings(); settings->setAccessibilityEnabled(true); - // TODO(dmazzoni): remove this on Android while still supporting - // moving by granularities. +#if defined(OS_ANDROID) + // Password values are only passed through on Android. + settings->setAccessibilityPasswordValuesEnabled(true); +#endif + +#if !defined(OS_ANDROID) + // Inline text boxes are enabled for all nodes on all except Android. settings->setInlineTextBoxAccessibilityEnabled(true); +#endif const WebDocument& document = GetMainDocument(); if (!document.isNull()) { @@ -71,6 +77,8 @@ bool RendererAccessibility::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(AccessibilityMsg_SetTextSelection, OnSetTextSelection) IPC_MESSAGE_HANDLER(AccessibilityMsg_SetValue, OnSetValue) IPC_MESSAGE_HANDLER(AccessibilityMsg_HitTest, OnHitTest) + IPC_MESSAGE_HANDLER(AccessibilityMsg_SetAccessibilityFocus, + OnSetAccessibilityFocus) IPC_MESSAGE_HANDLER(AccessibilityMsg_Reset, OnReset) IPC_MESSAGE_HANDLER(AccessibilityMsg_FatalError, OnFatalError) IPC_MESSAGE_UNHANDLED(handled = false) @@ -341,6 +349,26 @@ void RendererAccessibility::OnHitTest(gfx::Point point) { HandleAXEvent(obj, ui::AX_EVENT_HOVER); } +void RendererAccessibility::OnSetAccessibilityFocus(int acc_obj_id) { + if (tree_source_.accessibility_focus_id() == acc_obj_id) + return; + + tree_source_.set_accessiblity_focus_id(acc_obj_id); + + const WebDocument& document = GetMainDocument(); + if (document.isNull()) + return; + + WebAXObject obj = document.accessibilityObjectFromID(acc_obj_id); + + // This object may not be a leaf node. Force the whole subtree to be + // re-serialized. + serializer_.DeleteClientSubtree(obj); + + // Explicitly send a tree change update event now. + HandleAXEvent(obj, ui::AX_EVENT_TREE_CHANGED); +} + void RendererAccessibility::OnReset(int reset_token) { reset_token_ = reset_token; serializer_.Reset(); @@ -460,6 +488,7 @@ void RendererAccessibility::OnSetValue( } obj.setValue(value); + HandleAXEvent(obj, ui::AX_EVENT_VALUE_CHANGED); } } // namespace content diff --git a/content/renderer/accessibility/renderer_accessibility.h b/content/renderer/accessibility/renderer_accessibility.h index 151d193c1f327..2c3d8e846b4aa 100644 --- a/content/renderer/accessibility/renderer_accessibility.h +++ b/content/renderer/accessibility/renderer_accessibility.h @@ -96,6 +96,7 @@ class CONTENT_EXPORT RendererAccessibility : public RenderFrameObserver { void OnEventsAck(); void OnFatalError(); void OnHitTest(gfx::Point point); + void OnSetAccessibilityFocus(int acc_obj_id); void OnReset(int reset_token); void OnScrollToMakeVisible(int acc_obj_id, gfx::Rect subfocus); void OnScrollToPoint(int acc_obj_id, gfx::Point point); diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc index 6d0768bc43578..1308e7ce4b187 100644 --- a/content/renderer/gpu/render_widget_compositor.cc +++ b/content/renderer/gpu/render_widget_compositor.cc @@ -392,7 +392,12 @@ scoped_ptr RenderWidgetCompositor::Create( #elif !defined(OS_MACOSX) if (ui::IsOverlayScrollbarEnabled()) { +#if defined(OS_TIZEN) + // Tizen fades out the scrollbar after contents interaction ends. + settings.scrollbar_animator = cc::LayerTreeSettings::LinearFade; +#else settings.scrollbar_animator = cc::LayerTreeSettings::Thinning; +#endif settings.solid_color_scrollbar_color = SkColorSetARGB(128, 128, 128, 128); } else if (cmd->HasSwitch(cc::switches::kEnablePinchVirtualViewport)) { // use_pinch_zoom_scrollbars is only true on desktop when non-overlay diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc index 869bab6d0665d..f23bd44b4a8c0 100644 --- a/content/renderer/media/android/webmediaplayer_android.cc +++ b/content/renderer/media/android/webmediaplayer_android.cc @@ -4,6 +4,7 @@ #include "content/renderer/media/android/webmediaplayer_android.h" +#include #include #include "base/android/build_info.h" @@ -743,7 +744,7 @@ void WebMediaPlayerAndroid::OnMediaMetadataChanged( DCHECK(main_thread_checker_.CalledOnValidThread()); bool need_to_signal_duration_changed = false; - if (is_local_resource_) + if (is_local_resource_ || url_.SchemeIs("app")) UpdateNetworkState(WebMediaPlayer::NetworkStateLoaded); // Update duration, if necessary, prior to ready state updates that may diff --git a/content/renderer/media/media_stream_audio_processor.cc b/content/renderer/media/media_stream_audio_processor.cc index 68d69c706257d..548e74f5a2af1 100644 --- a/content/renderer/media/media_stream_audio_processor.cc +++ b/content/renderer/media/media_stream_audio_processor.cc @@ -19,7 +19,6 @@ #include "media/base/audio_fifo.h" #include "media/base/channel_layout.h" #include "third_party/WebKit/public/platform/WebMediaConstraints.h" -#include "third_party/libjingle/overrides/init_webrtc.h" #include "third_party/libjingle/source/talk/app/webrtc/mediaconstraintsinterface.h" #include "third_party/webrtc/modules/audio_processing/typing_detection.h" @@ -455,7 +454,7 @@ void MediaStreamAudioProcessor::InitializeAudioProcessingModule( #endif // Create and configure the webrtc::AudioProcessing. - audio_processing_.reset(CreateWebRtcAudioProcessing(config)); + audio_processing_.reset(webrtc::AudioProcessing::Create(config)); // Enable the audio processing components. if (echo_cancellation) { diff --git a/content/renderer/media/media_stream_audio_processor_options.cc b/content/renderer/media/media_stream_audio_processor_options.cc index d7e773d723df6..537ef908b14a9 100644 --- a/content/renderer/media/media_stream_audio_processor_options.cc +++ b/content/renderer/media/media_stream_audio_processor_options.cc @@ -326,10 +326,15 @@ void EnableTypingDetection(AudioProcessing* audio_processing, void StartEchoCancellationDump(AudioProcessing* audio_processing, base::File aec_dump_file) { DCHECK(aec_dump_file.IsValid()); - if (audio_processing->StartDebugRecordingForPlatformFile( - aec_dump_file.TakePlatformFile())) { - DLOG(ERROR) << "Fail to start AEC debug recording"; + + FILE* stream = base::FileToFILE(aec_dump_file.Pass(), "w"); + if (!stream) { + LOG(ERROR) << "Failed to open AEC dump file"; + return; } + + if (audio_processing->StartDebugRecording(stream)) + DLOG(ERROR) << "Fail to start AEC debug recording"; } void StopEchoCancellationDump(AudioProcessing* audio_processing) { diff --git a/content/renderer/media/webrtc/media_stream_track_metrics.cc b/content/renderer/media/webrtc/media_stream_track_metrics.cc index d4ce6b450fd90..d6962c3f91cff 100644 --- a/content/renderer/media/webrtc/media_stream_track_metrics.cc +++ b/content/renderer/media/webrtc/media_stream_track_metrics.cc @@ -9,6 +9,7 @@ #include #include "base/md5.h" +#include "base/thread_task_runner_handle.h" #include "content/common/media/media_stream_track_metrics_host_messages.h" #include "content/renderer/render_thread_impl.h" #include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h" @@ -20,38 +21,103 @@ using webrtc::PeerConnectionInterface; using webrtc::VideoTrackVector; namespace content { +namespace { +typedef std::set IdSet; + +template +IdSet GetTrackIds(const std::vector>& tracks) { + IdSet track_ids; + for (const auto& track : tracks) + track_ids.insert(track->id()); + return track_ids; +} -class MediaStreamTrackMetricsObserver : public webrtc::ObserverInterface { +// TODO(tommi): Consolidate this and TrackObserver since these implementations +// are fundamentally achieving the same thing (aside from specific logic inside +// the OnChanged callbacks). +class MediaStreamObserver + : public base::RefCountedThreadSafe, + public webrtc::ObserverInterface { + public: + typedef base::Callback< + void(const IdSet& audio_track_ids, const IdSet& video_track_ids)> + OnChangedCallback; + + MediaStreamObserver( + const OnChangedCallback& callback, + const scoped_refptr& main_thread, + webrtc::MediaStreamInterface* stream) + : main_thread_(main_thread), stream_(stream), callback_(callback) { + signaling_thread_.DetachFromThread(); + stream_->RegisterObserver(this); + } + + const scoped_refptr& stream() const { + DCHECK(main_thread_->BelongsToCurrentThread()); + return stream_; + } + + void Unregister() { + DCHECK(main_thread_->BelongsToCurrentThread()); + callback_.Reset(); + stream_->UnregisterObserver(this); + stream_ = nullptr; + } + + private: + friend class base::RefCountedThreadSafe; + ~MediaStreamObserver() override { + DCHECK(!stream_.get()) << "must have been unregistered before deleting"; + } + + // webrtc::ObserverInterface implementation. + void OnChanged() override { + DCHECK(signaling_thread_.CalledOnValidThread()); + main_thread_->PostTask(FROM_HERE, + base::Bind(&MediaStreamObserver::OnChangedOnMainThread, this, + GetTrackIds(stream_->GetAudioTracks()), + GetTrackIds(stream_->GetVideoTracks()))); + } + + void OnChangedOnMainThread(const IdSet& audio_track_ids, + const IdSet& video_track_ids) { + DCHECK(main_thread_->BelongsToCurrentThread()); + if (!callback_.is_null()) + callback_.Run(audio_track_ids, video_track_ids); + } + + const scoped_refptr main_thread_; + scoped_refptr stream_; + OnChangedCallback callback_; // Only touched on the main thread. + base::ThreadChecker signaling_thread_; +}; + +} // namespace + +class MediaStreamTrackMetricsObserver { public: MediaStreamTrackMetricsObserver( MediaStreamTrackMetrics::StreamType stream_type, MediaStreamInterface* stream, MediaStreamTrackMetrics* owner); - ~MediaStreamTrackMetricsObserver() override; + ~MediaStreamTrackMetricsObserver(); // Sends begin/end messages for all tracks currently tracked. void SendLifetimeMessages(MediaStreamTrackMetrics::LifetimeEvent event); - MediaStreamInterface* stream() { return stream_; } - MediaStreamTrackMetrics::StreamType stream_type() { return stream_type_; } - - private: - typedef std::set IdSet; + MediaStreamInterface* stream() { + DCHECK(thread_checker_.CalledOnValidThread()); + return observer_->stream().get(); + } - // webrtc::ObserverInterface implementation. - void OnChanged() override; - - template - IdSet GetTrackIds(const std::vector >& tracks) { - IdSet track_ids; - typename std::vector >::const_iterator it = - tracks.begin(); - for (; it != tracks.end(); ++it) { - track_ids.insert((*it)->id()); - } - return track_ids; + MediaStreamTrackMetrics::StreamType stream_type() { + DCHECK(thread_checker_.CalledOnValidThread()); + return stream_type_; } + private: + void OnChanged(const IdSet& audio_track_ids, const IdSet& video_track_ids); + void ReportAddedAndRemovedTracks( const IdSet& new_ids, const IdSet& old_ids, @@ -72,10 +138,11 @@ class MediaStreamTrackMetricsObserver : public webrtc::ObserverInterface { IdSet video_track_ids_; MediaStreamTrackMetrics::StreamType stream_type_; - rtc::scoped_refptr stream_; + scoped_refptr observer_; // Non-owning. MediaStreamTrackMetrics* owner_; + base::ThreadChecker thread_checker_; }; namespace { @@ -101,20 +168,26 @@ MediaStreamTrackMetricsObserver::MediaStreamTrackMetricsObserver( MediaStreamTrackMetrics* owner) : has_reported_start_(false), has_reported_end_(false), + audio_track_ids_(GetTrackIds(stream->GetAudioTracks())), + video_track_ids_(GetTrackIds(stream->GetVideoTracks())), stream_type_(stream_type), - stream_(stream), + observer_(new MediaStreamObserver( + base::Bind(&MediaStreamTrackMetricsObserver::OnChanged, + base::Unretained(this)), + base::ThreadTaskRunnerHandle::Get(), + stream)), owner_(owner) { - OnChanged(); // To populate initial tracks. - stream_->RegisterObserver(this); } MediaStreamTrackMetricsObserver::~MediaStreamTrackMetricsObserver() { - stream_->UnregisterObserver(this); + DCHECK(thread_checker_.CalledOnValidThread()); + observer_->Unregister(); SendLifetimeMessages(MediaStreamTrackMetrics::DISCONNECTED); } void MediaStreamTrackMetricsObserver::SendLifetimeMessages( MediaStreamTrackMetrics::LifetimeEvent event) { + DCHECK(thread_checker_.CalledOnValidThread()); if (event == MediaStreamTrackMetrics::CONNECTED) { // Both ICE CONNECTED and COMPLETED can trigger the first // start-of-life event, so we only report the first. @@ -146,33 +219,31 @@ void MediaStreamTrackMetricsObserver::SendLifetimeMessages( } } -void MediaStreamTrackMetricsObserver::OnChanged() { - AudioTrackVector all_audio_tracks = stream_->GetAudioTracks(); - IdSet all_audio_track_ids = GetTrackIds(all_audio_tracks); - - VideoTrackVector all_video_tracks = stream_->GetVideoTracks(); - IdSet all_video_track_ids = GetTrackIds(all_video_tracks); +void MediaStreamTrackMetricsObserver::OnChanged( + const IdSet& audio_track_ids, const IdSet& video_track_ids) { + DCHECK(thread_checker_.CalledOnValidThread()); // We only report changes after our initial report, and never after // our last report. if (has_reported_start_ && !has_reported_end_) { - ReportAddedAndRemovedTracks(all_audio_track_ids, + ReportAddedAndRemovedTracks(audio_track_ids, audio_track_ids_, MediaStreamTrackMetrics::AUDIO_TRACK); - ReportAddedAndRemovedTracks(all_video_track_ids, + ReportAddedAndRemovedTracks(video_track_ids, video_track_ids_, MediaStreamTrackMetrics::VIDEO_TRACK); } // We always update our sets of tracks. - audio_track_ids_ = all_audio_track_ids; - video_track_ids_ = all_video_track_ids; + audio_track_ids_ = audio_track_ids; + video_track_ids_ = video_track_ids; } void MediaStreamTrackMetricsObserver::ReportAddedAndRemovedTracks( const IdSet& new_ids, const IdSet& old_ids, MediaStreamTrackMetrics::TrackType track_type) { + DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(has_reported_start_ && !has_reported_end_); IdSet added_tracks = base::STLSetDifference(new_ids, old_ids); @@ -187,6 +258,7 @@ void MediaStreamTrackMetricsObserver::ReportTracks( const IdSet& ids, MediaStreamTrackMetrics::TrackType track_type, MediaStreamTrackMetrics::LifetimeEvent event) { + DCHECK(thread_checker_.CalledOnValidThread()); for (IdSet::const_iterator it = ids.begin(); it != ids.end(); ++it) { owner_->SendLifetimeMessage(*it, track_type, event, stream_type_); } diff --git a/content/renderer/media/webrtc/media_stream_track_metrics_unittest.cc b/content/renderer/media/webrtc/media_stream_track_metrics_unittest.cc index dcf1b13da326b..d18c04f9e4ce7 100644 --- a/content/renderer/media/webrtc/media_stream_track_metrics_unittest.cc +++ b/content/renderer/media/webrtc/media_stream_track_metrics_unittest.cc @@ -2,6 +2,10 @@ // 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/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/threading/thread.h" #include "content/renderer/media/webrtc/media_stream_track_metrics.h" #include "content/renderer/media/webrtc/mock_peer_connection_dependency_factory.h" #include "testing/gmock/include/gmock/gmock.h" @@ -78,16 +82,56 @@ class MockMediaStreamTrackMetrics : public MediaStreamTrackMetrics { class MediaStreamTrackMetricsTest : public testing::Test { public: + MediaStreamTrackMetricsTest() : signaling_thread_("signaling_thread") {} void SetUp() override { metrics_.reset(new MockMediaStreamTrackMetrics()); stream_ = new rtc::RefCountedObject("stream"); + signaling_thread_.Start(); } void TearDown() override { + signaling_thread_.Stop(); metrics_.reset(); stream_ = NULL; } + // Adds an audio track to |stream_| on the signaling thread to simulate how + // notifications will be fired in Chrome. + template + void AddTrack(TrackType* track) { + // Explicitly casting to this type is necessary since the + // MediaStreamInterface has two methods with the same name. + typedef bool (MediaStreamInterface::*AddTrack)(TrackType*); + base::RunLoop run_loop; + signaling_thread_.task_runner()->PostTaskAndReply(FROM_HERE, + base::Bind( + base::IgnoreResult(&MediaStreamInterface::AddTrack), + stream_, track), + run_loop.QuitClosure()); + run_loop.Run(); + } + + template + void RemoveTrack(TrackType* track) { + // Explicitly casting to this type is necessary since the + // MediaStreamInterface has two methods with the same name. + typedef bool (MediaStreamInterface::*RemoveTrack)(TrackType*); + base::RunLoop run_loop; + signaling_thread_.task_runner()->PostTaskAndReply(FROM_HERE, + base::Bind( + base::IgnoreResult(&MediaStreamInterface::RemoveTrack), + stream_, track), + run_loop.QuitClosure()); + run_loop.Run(); + } + + // Convenience methods to cast the mock track types into their webrtc + // equivalents. + void AddAudioTrack(AudioTrackInterface* track) { AddTrack(track); } + void RemoveAudioTrack(AudioTrackInterface* track) { RemoveTrack(track); } + void AddVideoTrack(VideoTrackInterface* track) { AddTrack(track); } + void RemoveVideoTrack(VideoTrackInterface* track) { RemoveTrack(track); } + scoped_refptr MakeAudioTrack(std::string id) { return new rtc::RefCountedObject(id); } @@ -98,6 +142,9 @@ class MediaStreamTrackMetricsTest : public testing::Test { scoped_ptr metrics_; scoped_refptr stream_; + + base::MessageLoopForUI message_loop_; + base::Thread signaling_thread_; }; TEST_F(MediaStreamTrackMetricsTest, MakeUniqueId) { @@ -262,7 +309,7 @@ TEST_F(MediaStreamTrackMetricsTest, RemoteStreamTrackAdded) { MediaStreamTrackMetrics::AUDIO_TRACK, MediaStreamTrackMetrics::CONNECTED, MediaStreamTrackMetrics::RECEIVED_STREAM)); - stream_->AddTrack(added.get()); + AddAudioTrack(added.get()); EXPECT_CALL(*metrics_, SendLifetimeMessage("initial", @@ -321,7 +368,7 @@ TEST_F(MediaStreamTrackMetricsTest, LocalStreamModificationsBeforeAndAfter) { // This gets added after we start observing, but no lifetime message // should be sent at this point since the call is not connected. It // should get sent only once it gets connected. - stream_->AddTrack(second.get()); + AddAudioTrack(second.get()); EXPECT_CALL(*metrics_, SendLifetimeMessage("first", @@ -350,7 +397,7 @@ TEST_F(MediaStreamTrackMetricsTest, LocalStreamModificationsBeforeAndAfter) { // This happens after the call is disconnected so no lifetime // message should be sent. - stream_->RemoveTrack(first.get()); + RemoveAudioTrack(first.get()); } TEST_F(MediaStreamTrackMetricsTest, RemoteStreamMultipleDisconnects) { @@ -374,7 +421,7 @@ TEST_F(MediaStreamTrackMetricsTest, RemoteStreamMultipleDisconnects) { metrics_->IceConnectionChange( PeerConnectionInterface::kIceConnectionDisconnected); metrics_->IceConnectionChange(PeerConnectionInterface::kIceConnectionFailed); - stream_->RemoveTrack(audio.get()); + RemoveAudioTrack(audio.get()); } TEST_F(MediaStreamTrackMetricsTest, RemoteStreamConnectDisconnectTwice) { @@ -400,7 +447,7 @@ TEST_F(MediaStreamTrackMetricsTest, RemoteStreamConnectDisconnectTwice) { PeerConnectionInterface::kIceConnectionDisconnected); } - stream_->RemoveTrack(audio.get()); + RemoveAudioTrack(audio.get()); } TEST_F(MediaStreamTrackMetricsTest, LocalStreamRemovedNoDisconnect) { @@ -465,33 +512,33 @@ TEST_F(MediaStreamTrackMetricsTest, LocalStreamLargerTest) { MediaStreamTrackMetrics::AUDIO_TRACK, MediaStreamTrackMetrics::CONNECTED, MediaStreamTrackMetrics::SENT_STREAM)); - stream_->AddTrack(audio2.get()); + AddAudioTrack(audio2.get()); EXPECT_CALL(*metrics_, SendLifetimeMessage("video2", MediaStreamTrackMetrics::VIDEO_TRACK, MediaStreamTrackMetrics::CONNECTED, MediaStreamTrackMetrics::SENT_STREAM)); - stream_->AddTrack(video2.get()); + AddVideoTrack(video2.get()); EXPECT_CALL(*metrics_, SendLifetimeMessage("audio1", MediaStreamTrackMetrics::AUDIO_TRACK, MediaStreamTrackMetrics::DISCONNECTED, MediaStreamTrackMetrics::SENT_STREAM)); - stream_->RemoveTrack(audio1.get()); + RemoveAudioTrack(audio1.get()); EXPECT_CALL(*metrics_, SendLifetimeMessage("audio3", MediaStreamTrackMetrics::AUDIO_TRACK, MediaStreamTrackMetrics::CONNECTED, MediaStreamTrackMetrics::SENT_STREAM)); - stream_->AddTrack(audio3.get()); + AddAudioTrack(audio3.get()); EXPECT_CALL(*metrics_, SendLifetimeMessage("video3", MediaStreamTrackMetrics::VIDEO_TRACK, MediaStreamTrackMetrics::CONNECTED, MediaStreamTrackMetrics::SENT_STREAM)); - stream_->AddTrack(video3.get()); + AddVideoTrack(video3.get()); // Add back audio1 EXPECT_CALL(*metrics_, @@ -499,33 +546,33 @@ TEST_F(MediaStreamTrackMetricsTest, LocalStreamLargerTest) { MediaStreamTrackMetrics::AUDIO_TRACK, MediaStreamTrackMetrics::CONNECTED, MediaStreamTrackMetrics::SENT_STREAM)); - stream_->AddTrack(audio1.get()); + AddAudioTrack(audio1.get()); EXPECT_CALL(*metrics_, SendLifetimeMessage("audio2", MediaStreamTrackMetrics::AUDIO_TRACK, MediaStreamTrackMetrics::DISCONNECTED, MediaStreamTrackMetrics::SENT_STREAM)); - stream_->RemoveTrack(audio2.get()); + RemoveAudioTrack(audio2.get()); EXPECT_CALL(*metrics_, SendLifetimeMessage("video2", MediaStreamTrackMetrics::VIDEO_TRACK, MediaStreamTrackMetrics::DISCONNECTED, MediaStreamTrackMetrics::SENT_STREAM)); - stream_->RemoveTrack(video2.get()); + RemoveVideoTrack(video2.get()); EXPECT_CALL(*metrics_, SendLifetimeMessage("audio1", MediaStreamTrackMetrics::AUDIO_TRACK, MediaStreamTrackMetrics::DISCONNECTED, MediaStreamTrackMetrics::SENT_STREAM)); - stream_->RemoveTrack(audio1.get()); + RemoveAudioTrack(audio1.get()); EXPECT_CALL(*metrics_, SendLifetimeMessage("video1", MediaStreamTrackMetrics::VIDEO_TRACK, MediaStreamTrackMetrics::DISCONNECTED, MediaStreamTrackMetrics::SENT_STREAM)); - stream_->RemoveTrack(video1.get()); + RemoveVideoTrack(video1.get()); EXPECT_CALL(*metrics_, SendLifetimeMessage("audio3", diff --git a/content/renderer/media/webrtc_audio_capturer.cc b/content/renderer/media/webrtc_audio_capturer.cc index 3299987d67b8e..45034e8b2f4eb 100644 --- a/content/renderer/media/webrtc_audio_capturer.cc +++ b/content/renderer/media/webrtc_audio_capturer.cc @@ -579,10 +579,13 @@ int WebRtcAudioCapturer::GetBufferSize(int sample_rate) const { // Use the native hardware buffer size in non peer connection mode when the // platform is using a native buffer size smaller than the PeerConnection - // buffer size. + // buffer size and audio processing is off. int hardware_buffer_size = device_info_.device.input.frames_per_buffer; if (!peer_connection_mode_ && hardware_buffer_size && - hardware_buffer_size <= peer_connection_buffer_size) { + hardware_buffer_size <= peer_connection_buffer_size && + !audio_processor_->has_audio_processing()) { + DVLOG(1) << "WebRtcAudioCapturer is using hardware buffer size " + << hardware_buffer_size; return hardware_buffer_size; } diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc index 4efdbb6458c95..5886cf1f71f30 100644 --- a/content/renderer/pepper/pepper_plugin_instance_impl.cc +++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc @@ -12,6 +12,7 @@ #include "base/memory/linked_ptr.h" #include "base/message_loop/message_loop.h" #include "base/metrics/histogram.h" +#include "base/metrics/sparse_histogram.h" #include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_offset_string_conversions.h" @@ -186,6 +187,13 @@ namespace content { namespace { +static const int kInfiniteRatio = 99999; + +#define UMA_HISTOGRAM_ASPECT_RATIO(name, width, height) \ + UMA_HISTOGRAM_SPARSE_SLOWLY( \ + name, \ + (height) ? ((width) * 100) / (height) : kInfiniteRatio); + // Check PP_TextInput_Type and ui::TextInputType are kept in sync. COMPILE_ASSERT(int(ui::TEXT_INPUT_TYPE_NONE) == int(PP_TEXTINPUT_TYPE_NONE), mismatching_enums); @@ -391,6 +399,15 @@ void InitLatencyInfo(ui::LatencyInfo* new_latency, } } +// Histogram tracking prevalence of tiny Flash instances. Units in pixels. +enum PluginFlashTinyContentSize { + TINY_CONTENT_SIZE_1_1 = 0, + TINY_CONTENT_SIZE_5_5 = 1, + TINY_CONTENT_SIZE_10_10 = 2, + TINY_CONTENT_SIZE_LARGE = 3, + TINY_CONTENT_SIZE_NUM_ITEMS +}; + // How the throttled power saver is unthrottled, if ever. // These numeric values are used in UMA logs; do not change them. enum PowerSaverUnthrottleMethod { @@ -400,7 +417,49 @@ enum PowerSaverUnthrottleMethod { UNTHROTTLE_METHOD_NUM_ITEMS }; -const char kPowerSaverUnthrottleHistogram[] = "Plugin.PowerSaverUnthrottle"; +const char kFlashClickSizeAspectRatioHistogram[] = + "Plugin.Flash.ClickSize.AspectRatio"; +const char kFlashClickSizeHeightHistogram[] = "Plugin.Flash.ClickSize.Height"; +const char kFlashClickSizeWidthHistogram[] = "Plugin.Flash.ClickSize.Width"; +const char kFlashTinyContentSizeHistogram[] = "Plugin.Flash.TinyContentSize"; +const char kPowerSaverUnthrottleHistogram[] = "Plugin.PowerSaver.Unthrottle"; + +// Record size metrics for all Flash instances. +void RecordFlashSizeMetric(int width, int height) { + PluginFlashTinyContentSize size = TINY_CONTENT_SIZE_LARGE; + + if (width <= 1 && height <= 1) + size = TINY_CONTENT_SIZE_1_1; + else if (width <= 5 && height <= 5) + size = TINY_CONTENT_SIZE_5_5; + else if (width <= 10 && height <= 10) + size = TINY_CONTENT_SIZE_10_10; + + UMA_HISTOGRAM_ENUMERATION(kFlashTinyContentSizeHistogram, size, + TINY_CONTENT_SIZE_NUM_ITEMS); +} + +// Records size metrics for Flash instances that are clicked. +void RecordFlashClickSizeMetric(int width, int height) { + base::HistogramBase* width_histogram = base::LinearHistogram::FactoryGet( + kFlashClickSizeWidthHistogram, + 0, // minimum width + 500, // maximum width + 100, // number of buckets. + base::HistogramBase::kUmaTargetedHistogramFlag); + width_histogram->Add(width); + + base::HistogramBase* height_histogram = base::LinearHistogram::FactoryGet( + kFlashClickSizeHeightHistogram, + 0, // minimum height + 400, // maximum height + 100, // number of buckets. + base::HistogramBase::kUmaTargetedHistogramFlag); + height_histogram->Add(height); + + UMA_HISTOGRAM_ASPECT_RATIO(kFlashClickSizeAspectRatioHistogram, width, + height); +} void RecordUnthrottleMethodMetric(PowerSaverUnthrottleMethod method) { UMA_HISTOGRAM_ENUMERATION(kPowerSaverUnthrottleHistogram, method, @@ -511,6 +570,7 @@ PepperPluginInstanceImpl::PepperPluginInstanceImpl( layer_bound_to_fullscreen_(false), layer_is_hardware_(false), plugin_url_(plugin_url), + has_been_clicked_(false), power_saver_enabled_(false), is_peripheral_content_(false), plugin_throttled_(false), @@ -606,11 +666,6 @@ PepperPluginInstanceImpl::PepperPluginInstanceImpl( if (GetContentClient()->renderer() && // NULL in unit tests. GetContentClient()->renderer()->IsExternalPepperPlugin(module->name())) external_document_load_ = true; - - if (IsFlashPlugin(module_.get())) { - RenderThread::Get()->RecordAction( - base::UserMetricsAction("Flash.PluginInstanceCreated")); - } } PepperPluginInstanceImpl::~PepperPluginInstanceImpl() { @@ -871,10 +926,16 @@ bool PepperPluginInstanceImpl::Initialize( if (!render_frame_) return false; + blink::WebRect bounds = container_->element().boundsInViewportSpace(); + if (IsFlashPlugin(module_.get())) { + RenderThread::Get()->RecordAction( + base::UserMetricsAction("Flash.PluginInstanceCreated")); + RecordFlashSizeMetric(bounds.width, bounds.height); + } + PluginPowerSaverHelper* power_saver_helper = render_frame_->plugin_power_saver_helper(); GURL content_origin = plugin_url_.GetOrigin(); - blink::WebRect bounds = container_->element().boundsInViewportSpace(); bool cross_origin = false; is_peripheral_content_ = @@ -1158,6 +1219,13 @@ bool PepperPluginInstanceImpl::HandleInputEvent( WebCursorInfo* cursor_info) { TRACE_EVENT0("ppapi", "PepperPluginInstanceImpl::HandleInputEvent"); + if (event.type == blink::WebInputEvent::MouseDown && !has_been_clicked_ && + IsFlashPlugin(module_.get())) { + has_been_clicked_ = true; + blink::WebRect bounds = container_->element().boundsInViewportSpace(); + RecordFlashClickSizeMetric(bounds.width, bounds.height); + } + if (event.type == blink::WebInputEvent::MouseUp && is_peripheral_content_) { is_peripheral_content_ = false; power_saver_enabled_ = false; diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.h b/content/renderer/pepper/pepper_plugin_instance_impl.h index 9f55084609a3c..c056a93bc11f3 100644 --- a/content/renderer/pepper/pepper_plugin_instance_impl.h +++ b/content/renderer/pepper/pepper_plugin_instance_impl.h @@ -713,6 +713,9 @@ class CONTENT_EXPORT PepperPluginInstanceImpl // Plugin URL. GURL plugin_url_; + // Set to true first time plugin is clicked. Used to collect metrics. + bool has_been_clicked_; + // Indicates whether this plugin may be throttled to reduce power consumption. // |power_saver_enabled_| implies |is_peripheral_content_|. bool power_saver_enabled_; diff --git a/content/renderer/pepper/plugin_power_saver_helper.cc b/content/renderer/pepper/plugin_power_saver_helper.cc index 365789c6835e6..3c60c16d2db8c 100644 --- a/content/renderer/pepper/plugin_power_saver_helper.cc +++ b/content/renderer/pepper/plugin_power_saver_helper.cc @@ -28,7 +28,7 @@ enum PeripheralHeuristicDecision { }; const char kPeripheralHeuristicHistogram[] = - "Plugin.PowerSaverPeripheralHeuristic"; + "Plugin.PowerSaver.PeripheralHeuristic"; // Maximum dimensions plug-in content may have while still being considered // peripheral content. These match the sizes used by Safari. diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 6088aba42308c..ec72834cbfa70 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc @@ -162,6 +162,11 @@ #include "content/renderer/media/crypto/renderer_cdm_manager.h" #endif +#if defined(OS_TIZEN) && defined(ENABLE_MURPHY) +#include "xwalk/tizen/renderer/media/renderer_mediaplayer_manager.h" +#include "xwalk/tizen/renderer/media/mediaplayer_impl.h" +#endif + using blink::WebContextMenuData; using blink::WebData; using blink::WebDataSource; @@ -584,6 +589,9 @@ RenderFrameImpl::RenderFrameImpl(RenderViewImpl* render_view, int routing_id) #endif #if defined(VIDEO_HOLE) contains_media_player_(false), +#endif +#if defined(OS_TIZEN) && defined(ENABLE_MURPHY) + media_player_manager_(NULL), #endif geolocation_dispatcher_(NULL), push_messaging_dispatcher_(NULL), @@ -1747,11 +1755,28 @@ blink::WebMediaPlayer* RenderFrameImpl::createMediaPlayer( render_thread->compositor_message_loop_proxy(), base::Bind(&EncryptedMediaPlayerSupportImpl::Create), initial_cdm); + +#if defined(OS_TIZEN) && defined(ENABLE_MURPHY) + tizen::MediaPlayerImpl* media_player = new tizen::MediaPlayerImpl( + frame, client, weak_factory_.GetWeakPtr(), + GetTizenMediaPlayerManager(), params); + return media_player; +#endif return new media::WebMediaPlayerImpl( frame, client, weak_factory_.GetWeakPtr(), nullptr, params); #endif // defined(OS_ANDROID) } +#if defined(OS_TIZEN) && defined(ENABLE_MURPHY) +tizen::RendererMediaPlayerManager* +RenderFrameImpl::GetTizenMediaPlayerManager() { + if (!media_player_manager_) + media_player_manager_ = new tizen::RendererMediaPlayerManager(this); + + return media_player_manager_; +} +#endif + blink::WebContentDecryptionModule* RenderFrameImpl::createContentDecryptionModule( blink::WebLocalFrame* frame, diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index 77d4941458969..369f177b51378 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h @@ -59,6 +59,12 @@ class Range; class Rect; } +#if defined(OS_TIZEN) && defined(ENABLE_MURPHY) +namespace tizen { +class RendererMediaPlayerManager; +} +#endif + namespace content { class ChildFrameCompositingHelper; @@ -672,6 +678,8 @@ class CONTENT_EXPORT RenderFrameImpl blink::WebContentDecryptionModule* initial_cdm); RendererMediaPlayerManager* GetMediaPlayerManager(); +#elif defined(OS_TIZEN) && defined(ENABLE_MURPHY) + tizen::RendererMediaPlayerManager* GetTizenMediaPlayerManager(); #endif #if defined(ENABLE_BROWSER_CDMS) @@ -764,6 +772,8 @@ class CONTENT_EXPORT RenderFrameImpl // real media player in the browser process. It's okay to use a raw pointer // since it's a RenderFrameObserver. RendererMediaPlayerManager* media_player_manager_; +#elif defined(OS_TIZEN) && defined(ENABLE_MURPHY) + tizen::RendererMediaPlayerManager* media_player_manager_; #endif #if defined(ENABLE_BROWSER_CDMS) diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index 8566532a3d7fb..6984b13774362 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc @@ -1464,6 +1464,8 @@ void RenderThreadImpl::OnTempCrashWithData(const GURL& data) { } void RenderThreadImpl::OnUpdateTimezone() { + if (!blink_platform_impl_) + return; NotifyTimezoneChange(); } diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 56a719eb8be62..8af3bfe404019 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc @@ -1074,6 +1074,22 @@ void RenderView::ApplyWebPreferences(const WebPreferences& prefs, static_cast( prefs.v8_script_streaming_mode)); + // Crosswalk shared settings: + settings->setMainFrameClipsContent(false); + +#if defined(OS_TIZEN) + // Scrollbars should not be stylable. + settings->setAllowCustomScrollbarInMainFrame(false); + + // IME support + settings->setAutoZoomFocusedNodeToLegibleScale(true); + + // Enable double tap to zoom when zoomable. + settings->setDoubleTapToZoomEnabled(true); + + settings->setShrinksViewportContentToFit(true); +#endif + #if defined(OS_ANDROID) settings->setAllowCustomScrollbarInMainFrame(false); settings->setTextAutosizingEnabled(prefs.text_autosizing_enabled); @@ -3581,6 +3597,17 @@ GURL RenderViewImpl::GetURLForGraphicsContext3D() { void RenderViewImpl::OnSetFocus(bool enable) { RenderWidget::OnSetFocus(enable); + // Make VisibilityChange events work when a window has become visible + // or has been hidden. + if (webview()) { + if (enable) + webview()->setVisibilityState(blink::WebPageVisibilityStateVisible, + false); + else + webview()->setVisibilityState(blink::WebPageVisibilityStateHidden, + false); + } + #if defined(ENABLE_PLUGINS) if (webview() && webview()->isActive()) { // Notify all NPAPI plugins. @@ -4045,6 +4072,9 @@ bool RenderViewImpl::didTapMultipleTargets( const WebSize& inner_viewport_offset, const WebRect& touch_rect, const WebVector& target_rects) { + if (!switches::IsLinkDisambiguationPopupEnabled()) + return false; + // Never show a disambiguation popup when accessibility is enabled, // as this interferes with "touch exploration". AccessibilityMode accessibility_mode = diff --git a/content/test/data/accessibility/aria-valuemax-expected-android.txt b/content/test/data/accessibility/aria-valuemax-expected-android.txt index 0c5f2444fcd8b..20bfb69cbcf1b 100644 --- a/content/test/data/accessibility/aria-valuemax-expected-android.txt +++ b/content/test/data/accessibility/aria-valuemax-expected-android.txt @@ -1,5 +1,5 @@ android.webkit.WebView focusable focused scrollable - android.widget.ProgressBar range item_index=51 item_count=101 range_min=1 range_max=101 range_current_value=51 + android.widget.ProgressBar range item_index=50 item_count=100 range_min=1 range_max=101 range_current_value=51 android.view.View range range_min=2 range_max=102 range_current_value=52 - android.widget.SeekBar range item_index=53 item_count=103 range_min=3 range_max=103 range_current_value=53 - android.widget.EditText range_min=4 range_max=104 range_current_value=54 + android.widget.SeekBar range item_index=50 item_count=100 range_min=3 range_max=103 range_current_value=53 + android.widget.EditText range_min=4 range_max=104 range_current_value=54 \ No newline at end of file diff --git a/content/test/data/accessibility/aria-valuemin-expected-android.txt b/content/test/data/accessibility/aria-valuemin-expected-android.txt index 0c5f2444fcd8b..20bfb69cbcf1b 100644 --- a/content/test/data/accessibility/aria-valuemin-expected-android.txt +++ b/content/test/data/accessibility/aria-valuemin-expected-android.txt @@ -1,5 +1,5 @@ android.webkit.WebView focusable focused scrollable - android.widget.ProgressBar range item_index=51 item_count=101 range_min=1 range_max=101 range_current_value=51 + android.widget.ProgressBar range item_index=50 item_count=100 range_min=1 range_max=101 range_current_value=51 android.view.View range range_min=2 range_max=102 range_current_value=52 - android.widget.SeekBar range item_index=53 item_count=103 range_min=3 range_max=103 range_current_value=53 - android.widget.EditText range_min=4 range_max=104 range_current_value=54 + android.widget.SeekBar range item_index=50 item_count=100 range_min=3 range_max=103 range_current_value=53 + android.widget.EditText range_min=4 range_max=104 range_current_value=54 \ No newline at end of file diff --git a/content/test/data/accessibility/aria-valuenow-expected-android.txt b/content/test/data/accessibility/aria-valuenow-expected-android.txt index 9d59be2bf99a9..9bc7f1d200688 100644 --- a/content/test/data/accessibility/aria-valuenow-expected-android.txt +++ b/content/test/data/accessibility/aria-valuenow-expected-android.txt @@ -1,2 +1,2 @@ android.webkit.WebView focusable focused scrollable - android.widget.ProgressBar range item_index=3 range_current_value=3 + android.widget.ProgressBar range item_count=100 range_current_value=3 \ No newline at end of file diff --git a/content/test/data/accessibility/input-color-expected-android.txt b/content/test/data/accessibility/input-color-expected-android.txt index 947af64d74912..daa591a888a46 100644 --- a/content/test/data/accessibility/input-color-expected-android.txt +++ b/content/test/data/accessibility/input-color-expected-android.txt @@ -1,3 +1,3 @@ android.webkit.WebView focusable focused scrollable android.view.View - android.view.View focusable + android.widget.Spinner clickable focusable name='#FF9900' diff --git a/content/test/data/accessibility/input-date-expected-android.txt b/content/test/data/accessibility/input-date-expected-android.txt index 3873afad82b77..263e6906be58e 100644 --- a/content/test/data/accessibility/input-date-expected-android.txt +++ b/content/test/data/accessibility/input-date-expected-android.txt @@ -1,4 +1,3 @@ android.webkit.WebView focusable focused scrollable android.view.View - android.view.View focusable input_type=20 - android.view.View + android.widget.Spinner clickable focusable name='2008-09-01' input_type=20 diff --git a/content/test/data/accessibility/input-date-expected-mac.txt b/content/test/data/accessibility/input-date-expected-mac.txt index 01b10ed644842..351a3ee112745 100644 --- a/content/test/data/accessibility/input-date-expected-mac.txt +++ b/content/test/data/accessibility/input-date-expected-mac.txt @@ -1,14 +1,14 @@ -AXWebArea - AXGroup - AXUnknown - AXGroup - AXGroup - AXSlider AXValue='0' - AXStaticText AXValue='/' - AXSlider AXValue='0' - AXStaticText AXValue='/' - AXSlider AXValue='0' - AXPopUpButton - AXSlider AXValue='0' - AXButton - AXButton +AXWebArea AXRoleDescription='HTML content' + AXGroup AXRoleDescription='group' + AXDateField AXRoleDescription='date field' AXValue='2008-09-01' + AXGroup AXRoleDescription='group' + AXGroup AXRoleDescription='group' + AXIncrementor AXRoleDescription='stepper' AXValue='9' + AXStaticText AXRoleDescription='text' AXValue='/' + AXIncrementor AXRoleDescription='stepper' AXValue='1' + AXStaticText AXRoleDescription='text' AXValue='/' + AXIncrementor AXRoleDescription='stepper' AXValue='2008' + AXPopUpButton AXRoleDescription='pop up button' + AXIncrementor AXRoleDescription='stepper' AXValue='0' + AXButton AXRoleDescription='button' + AXButton AXRoleDescription='button' diff --git a/content/test/data/accessibility/input-date.html b/content/test/data/accessibility/input-date.html index 7bf6e0ddd39a7..e6dd2ab2813a1 100644 --- a/content/test/data/accessibility/input-date.html +++ b/content/test/data/accessibility/input-date.html @@ -2,7 +2,7 @@ - + diff --git a/content/test/data/accessibility/input-range-expected-android.txt b/content/test/data/accessibility/input-range-expected-android.txt index 8e8d7f4fcc745..d4165d5adb837 100644 --- a/content/test/data/accessibility/input-range-expected-android.txt +++ b/content/test/data/accessibility/input-range-expected-android.txt @@ -1,3 +1,3 @@ android.webkit.WebView focusable focused scrollable android.view.View - android.widget.SeekBar focusable range item_index=5 item_count=10 range_min=1 range_max=10 range_current_value=5 + android.widget.SeekBar focusable range item_index=44 item_count=100 range_min=1 range_max=10 range_current_value=5 diff --git a/content/test/data/accessibility/input-time-expected-android.txt b/content/test/data/accessibility/input-time-expected-android.txt index 254953a0f0e92..7bfa62359ab0e 100644 --- a/content/test/data/accessibility/input-time-expected-android.txt +++ b/content/test/data/accessibility/input-time-expected-android.txt @@ -1,4 +1,3 @@ android.webkit.WebView focusable focused scrollable android.view.View - android.view.View focusable input_type=36 - android.view.View + android.widget.Spinner clickable focusable name='00:00:00' input_type=36 diff --git a/content/test/data/accessibility/input-time-expected-mac.txt b/content/test/data/accessibility/input-time-expected-mac.txt index 1dfa0b4e1fc12..34bbed46f71ac 100644 --- a/content/test/data/accessibility/input-time-expected-mac.txt +++ b/content/test/data/accessibility/input-time-expected-mac.txt @@ -1,12 +1,12 @@ AXWebArea AXRoleDescription='HTML content' AXGroup AXRoleDescription='group' - AXUnknown AXRoleDescription='unknown' + AXTimeField AXRoleDescription='time field' AXValue='00:00:00' AXGroup AXRoleDescription='group' AXGroup AXRoleDescription='group' - AXSlider AXRoleDescription='stepper' AXValue='0' + AXIncrementor AXRoleDescription='stepper' AXValue='12' AXStaticText AXRoleDescription='text' AXValue=':' - AXSlider AXRoleDescription='stepper' AXValue='0' - AXSlider AXRoleDescription='stepper' AXValue='0' - AXSlider AXRoleDescription='stepper' AXValue='0' + AXIncrementor AXRoleDescription='stepper' AXValue='0' + AXIncrementor AXRoleDescription='stepper' AXValue='1' + AXIncrementor AXRoleDescription='stepper' AXValue='0' AXButton AXRoleDescription='button' AXButton AXRoleDescription='button' diff --git a/content/test/data/accessibility/input-time.html b/content/test/data/accessibility/input-time.html index b1b2bf28d65ae..9fe33f718102c 100644 --- a/content/test/data/accessibility/input-time.html +++ b/content/test/data/accessibility/input-time.html @@ -4,6 +4,6 @@ --> - + diff --git a/content/test/data/accessibility/input-types-expected-android.txt b/content/test/data/accessibility/input-types-expected-android.txt index c9af06bebf571..f02b9bf758d8f 100644 --- a/content/test/data/accessibility/input-types-expected-android.txt +++ b/content/test/data/accessibility/input-types-expected-android.txt @@ -9,7 +9,7 @@ android.webkit.WebView focusable focused scrollable android.widget.CheckBox checkable clickable focusable name='Checkbox: ' android.view.View android.view.View clickable name='Color:' - android.view.View focusable + android.widget.Spinner clickable focusable name='#000000' android.view.View android.view.View clickable name='Email:' android.widget.EditText editable_text focusable input_type=209 @@ -28,7 +28,7 @@ android.webkit.WebView focusable focused scrollable android.widget.RadioButton checkable clickable focusable name='Radio: ' android.view.View android.view.View clickable name='Range:' - android.widget.SeekBar focusable range item_index=50 item_count=100 range_max=100 range_current_value=50 + android.widget.SeekBar clickable focusable range name='50' item_index=50 item_count=100 range_max=100 range_current_value=50 android.view.View android.view.View clickable name='Reset:' android.widget.Button clickable focusable name='Reset' diff --git a/content/test/data/accessibility/select-expected-android.txt b/content/test/data/accessibility/select-expected-android.txt index c7b982f0c4a0b..06559314e0d90 100644 --- a/content/test/data/accessibility/select-expected-android.txt +++ b/content/test/data/accessibility/select-expected-android.txt @@ -1,5 +1,5 @@ android.webkit.WebView focusable focused scrollable android.view.View - android.widget.Button clickable focusable name='Placeholder option' - android.widget.Button clickable focusable name='Option 2' - android.widget.Button clickable focusable name='Option 1' + android.widget.Spinner clickable focusable name='Placeholder option' + android.widget.Spinner clickable focusable name='Option 2' + android.widget.Spinner clickable focusable name='Option 1' diff --git a/device/hid/hid_service_mac.cc b/device/hid/hid_service_mac.cc index 6e091a851e7da..7d40cae88ff9d 100644 --- a/device/hid/hid_service_mac.cc +++ b/device/hid/hid_service_mac.cc @@ -133,6 +133,11 @@ void PopulateDeviceInfo(io_service_t service, HidDeviceInfo* device_info) { base::ScopedCFTypeRef hid_device( IOHIDDeviceCreate(kCFAllocatorDefault, service)); + if (!hid_device) { + VLOG(1) << "Unable to create IOHIDDevice object."; + return; + } + device_info->device_id = service_path; device_info->vendor_id = GetHidIntProperty(hid_device, CFSTR(kIOHIDVendorIDKey)); @@ -285,6 +290,12 @@ void HidServiceMac::Connect(const HidDeviceId& device_id, base::ScopedCFTypeRef hid_device( IOHIDDeviceCreate(kCFAllocatorDefault, service)); + if (!hid_device) { + VLOG(1) << "Unable to create IOHIDDevice object."; + task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); + return; + } + IOReturn result = IOHIDDeviceOpen(hid_device, kIOHIDOptionsTypeNone); if (result != kIOReturnSuccess) { VLOG(1) << "Failed to open device: " diff --git a/device/usb/usb_device_handle_impl.cc b/device/usb/usb_device_handle_impl.cc index 50c26092fae10..6f0e28684974f 100644 --- a/device/usb/usb_device_handle_impl.cc +++ b/device/usb/usb_device_handle_impl.cc @@ -498,9 +498,8 @@ void UsbDeviceHandleImpl::RefreshEndpointMap() { scoped_refptr UsbDeviceHandleImpl::GetClaimedInterfaceForEndpoint(unsigned char endpoint) { - unsigned char address = endpoint & LIBUSB_ENDPOINT_ADDRESS_MASK; - if (ContainsKey(endpoint_map_, address)) - return claimed_interfaces_[endpoint_map_[address]]; + if (ContainsKey(endpoint_map_, endpoint)) + return claimed_interfaces_[endpoint_map_[endpoint]]; return NULL; } diff --git a/extensions/browser/api/device_permissions_manager.cc b/extensions/browser/api/device_permissions_manager.cc index 2c43a86b6f856..43c2b7abd7101 100644 --- a/extensions/browser/api/device_permissions_manager.cc +++ b/extensions/browser/api/device_permissions_manager.cc @@ -324,11 +324,13 @@ void DevicePermissionsManager::Clear(const std::string& extension_id) { DCHECK(CalledOnValidThread()); ClearDevicePermissionEntries(ExtensionPrefs::Get(context_), extension_id); - std::map::iterator it = - extension_id_to_device_permissions_.find(extension_id); - if (it != extension_id_to_device_permissions_.end()) { - delete it->second; - extension_id_to_device_permissions_.erase(it); + DevicePermissions* device_permissions = Get(extension_id); + if (device_permissions) { + for (const auto& device_entry : device_permissions->ephemeral_devices_) { + device_entry->RemoveObserver(this); + } + extension_id_to_device_permissions_.erase(extension_id); + delete device_permissions; } } @@ -340,7 +342,11 @@ DevicePermissionsManager::DevicePermissionsManager( DevicePermissionsManager::~DevicePermissionsManager() { for (const auto& map_entry : extension_id_to_device_permissions_) { - delete map_entry.second; + DevicePermissions* device_permissions = map_entry.second; + for (const auto& device_entry : device_permissions->ephemeral_devices_) { + device_entry->RemoveObserver(this); + } + delete device_permissions; } } diff --git a/extensions/browser/app_window/app_window.cc b/extensions/browser/app_window/app_window.cc index c7990e1798487..8ce9cf646ce19 100644 --- a/extensions/browser/app_window/app_window.cc +++ b/extensions/browser/app_window/app_window.cc @@ -656,6 +656,7 @@ void AppWindow::SetContentSizeConstraints(const gfx::Size& min_size, } void AppWindow::Show(ShowType show_type) { + bool was_hidden = is_hidden_ || !has_been_shown_; is_hidden_ = false; if (CommandLine::ForCurrentProcess()->HasSwitch( @@ -676,7 +677,7 @@ void AppWindow::Show(ShowType show_type) { GetBaseWindow()->ShowInactive(); break; } - AppWindowRegistry::Get(browser_context_)->AppWindowShown(this); + AppWindowRegistry::Get(browser_context_)->AppWindowShown(this, was_hidden); has_been_shown_ = true; SendOnWindowShownIfShown(); diff --git a/extensions/browser/app_window/app_window_registry.cc b/extensions/browser/app_window/app_window_registry.cc index 48397f5f465ba..572c4b246cb20 100644 --- a/extensions/browser/app_window/app_window_registry.cc +++ b/extensions/browser/app_window/app_window_registry.cc @@ -60,7 +60,8 @@ void AppWindowRegistry::Observer::OnAppWindowRemoved(AppWindow* app_window) { void AppWindowRegistry::Observer::OnAppWindowHidden(AppWindow* app_window) { } -void AppWindowRegistry::Observer::OnAppWindowShown(AppWindow* app_window) { +void AppWindowRegistry::Observer::OnAppWindowShown(AppWindow* app_window, + bool was_shown) { } AppWindowRegistry::Observer::~Observer() { @@ -100,8 +101,9 @@ void AppWindowRegistry::AppWindowHidden(AppWindow* app_window) { FOR_EACH_OBSERVER(Observer, observers_, OnAppWindowHidden(app_window)); } -void AppWindowRegistry::AppWindowShown(AppWindow* app_window) { - FOR_EACH_OBSERVER(Observer, observers_, OnAppWindowShown(app_window)); +void AppWindowRegistry::AppWindowShown(AppWindow* app_window, bool was_hidden) { + FOR_EACH_OBSERVER(Observer, observers_, + OnAppWindowShown(app_window, was_hidden)); } void AppWindowRegistry::RemoveAppWindow(AppWindow* app_window) { diff --git a/extensions/browser/app_window/app_window_registry.h b/extensions/browser/app_window/app_window_registry.h index 7037953c4e93d..ed2cdc6aa8978 100644 --- a/extensions/browser/app_window/app_window_registry.h +++ b/extensions/browser/app_window/app_window_registry.h @@ -44,7 +44,7 @@ class AppWindowRegistry : public KeyedService { // it not visible. virtual void OnAppWindowHidden(AppWindow* app_window); // Called just after a app window was shown. - virtual void OnAppWindowShown(AppWindow* app_window); + virtual void OnAppWindowShown(AppWindow* app_window, bool was_hidden); protected: virtual ~Observer(); @@ -67,7 +67,7 @@ class AppWindowRegistry : public KeyedService { // Called by |app_window| when it is activated. void AppWindowActivated(AppWindow* app_window); void AppWindowHidden(AppWindow* app_window); - void AppWindowShown(AppWindow* app_window); + void AppWindowShown(AppWindow* app_window, bool was_hidden); void RemoveAppWindow(AppWindow* app_window); void AddObserver(Observer* observer); diff --git a/extensions/browser/updater/extension_downloader.cc b/extensions/browser/updater/extension_downloader.cc index 30680270fbb06..da4ff410bf4a2 100644 --- a/extensions/browser/updater/extension_downloader.cc +++ b/extensions/browser/updater/extension_downloader.cc @@ -952,13 +952,8 @@ ManifestFetchData* ExtensionDownloader::CreateManifestFetchData( const GURL& update_url, int request_id) { ManifestFetchData::PingMode ping_mode = ManifestFetchData::NO_PING; - if (update_url.DomainIs(ping_enabled_domain_.c_str())) { - if (enable_extra_update_metrics_) { - ping_mode = ManifestFetchData::PING_WITH_METRICS; - } else { - ping_mode = ManifestFetchData::PING; - } - } + if (update_url.DomainIs(ping_enabled_domain_.c_str())) + ping_mode = ManifestFetchData::PING_WITH_ENABLED_STATE; return new ManifestFetchData( update_url, request_id, brand_code_, manifest_query_params_, ping_mode); } diff --git a/extensions/browser/updater/manifest_fetch_data.cc b/extensions/browser/updater/manifest_fetch_data.cc index 2f73acb361058..6511a1eb6a8d0 100644 --- a/extensions/browser/updater/manifest_fetch_data.cc +++ b/extensions/browser/updater/manifest_fetch_data.cc @@ -22,7 +22,7 @@ namespace { // request. We want to stay under 2K because of proxies, etc. const int kExtensionsManifestMaxURLSize = 2000; -void AddMetricsToPing(std::string* ping_value, +void AddEnabledStateToPing(std::string* ping_value, const ManifestFetchData::PingData* ping_data) { *ping_value += "&e=" + std::string(ping_data->is_enabled ? "1" : "0"); if (!ping_data->is_enabled) { @@ -125,8 +125,8 @@ bool ManifestFetchData::AddExtension(const std::string& id, if (ping_data->rollcall_days == kNeverPinged || ping_data->rollcall_days > 0) { ping_value += "r=" + base::IntToString(ping_data->rollcall_days); - if (ping_mode_ == PING_WITH_METRICS) - AddMetricsToPing(&ping_value, ping_data); + if (ping_mode_ == PING_WITH_ENABLED_STATE) + AddEnabledStateToPing(&ping_value, ping_data); pings_[id].rollcall_days = ping_data->rollcall_days; pings_[id].is_enabled = ping_data->is_enabled; } diff --git a/extensions/browser/updater/manifest_fetch_data.h b/extensions/browser/updater/manifest_fetch_data.h index 8f33ab393ade2..6ff339630ebfb 100644 --- a/extensions/browser/updater/manifest_fetch_data.h +++ b/extensions/browser/updater/manifest_fetch_data.h @@ -30,8 +30,8 @@ class ManifestFetchData { // Ping without extra metrics. PING, - // Ping with extra metrics. - PING_WITH_METRICS, + // Ping with information about enabled/disabled state. + PING_WITH_ENABLED_STATE, }; // Each ping type is sent at most once per day. diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json index 5cb571e871761..262bae2537833 100644 --- a/extensions/common/api/_api_features.json +++ b/extensions/common/api/_api_features.json @@ -302,11 +302,6 @@ "dependencies": ["permission:usb"], "contexts": ["blessed_extension"] }, - "usb.getUserSelectedDevices": { - "channel": "dev", - "dependencies": ["permission:usb"], - "contexts": ["blessed_extension"] - }, "vpnProvider": { "dependencies": ["permission:vpnProvider"], "contexts": ["blessed_extension"] diff --git a/extensions/common/csp_validator.cc b/extensions/common/csp_validator.cc index 65edd0a3aaffb..23af91c75787c 100644 --- a/extensions/common/csp_validator.cc +++ b/extensions/common/csp_validator.cc @@ -54,6 +54,12 @@ bool isNonWildcardTLD(const std::string& url, if (end_of_host == std::string::npos) end_of_host = url.size(); + // A missing host such as "chrome-extension://" is invalid, but for backwards- + // compatibility, accept such CSP parts. They will be ignored by Blink anyway. + // TODO(robwu): Remove this special case once crbug.com/434773 is fixed. + if (start_of_host == end_of_host) + return true; + // Note: It is sufficient to only compare the first character against '*' // because the CSP only allows wildcards at the start of a directive, see // host-source and host-part at http://www.w3.org/TR/CSP2/#source-list-syntax diff --git a/extensions/common/csp_validator_unittest.cc b/extensions/common/csp_validator_unittest.cc index 9778a5a22d671..436d4502715c4 100644 --- a/extensions/common/csp_validator_unittest.cc +++ b/extensions/common/csp_validator_unittest.cc @@ -98,7 +98,9 @@ TEST(ExtensionCSPValidator, IsSecure) { "default-src 'self' *:*/", Manifest::TYPE_EXTENSION)); EXPECT_FALSE(ContentSecurityPolicyIsSecure( "default-src 'self' *:*/path", Manifest::TYPE_EXTENSION)); - EXPECT_FALSE(ContentSecurityPolicyIsSecure( + // "https://" is an invalid CSP, so it will be ignored by Blink. + // TODO(robwu): Change to EXPECT_FALSE once http://crbug.com/434773 is fixed. + EXPECT_TRUE(ContentSecurityPolicyIsSecure( "default-src 'self' https://", Manifest::TYPE_EXTENSION)); EXPECT_FALSE(ContentSecurityPolicyIsSecure( "default-src 'self' https://*:*", Manifest::TYPE_EXTENSION)); @@ -167,6 +169,11 @@ TEST(ExtensionCSPValidator, IsSecure) { "default-src 'self' https://*.googleapis.com", Manifest::TYPE_EXTENSION)); EXPECT_TRUE(ContentSecurityPolicyIsSecure( "default-src 'self' https://x.googleapis.com", Manifest::TYPE_EXTENSION)); + // "chrome-extension://" is an invalid CSP and ignored by Blink, but extension + // authors have been using this string anyway, so we cannot refuse this string + // until extensions can be loaded with an invalid CSP. http://crbug.com/434773 + EXPECT_TRUE(ContentSecurityPolicyIsSecure( + "default-src 'self' chrome-extension://", Manifest::TYPE_EXTENSION)); } TEST(ExtensionCSPValidator, IsSandboxed) { diff --git a/google_apis/gaia/oauth2_mint_token_flow.cc b/google_apis/gaia/oauth2_mint_token_flow.cc index 1b040cca75d1c..99562b0499a93 100644 --- a/google_apis/gaia/oauth2_mint_token_flow.cc +++ b/google_apis/gaia/oauth2_mint_token_flow.cc @@ -41,6 +41,8 @@ const char kOAuth2IssueTokenBodyFormat[] = "&scope=%s" "&client_id=%s" "&origin=%s"; +const char kOAuth2IssueTokenBodyFormatDeviceIdAddendum[] = + "&device_id=%s&device_type=chrome"; const char kIssueAdviceKey[] = "issueAdvice"; const char kIssueAdviceValueConsent[] = "consent"; const char kAccessTokenKey[] = "token"; @@ -101,8 +103,13 @@ OAuth2MintTokenFlow::Parameters::Parameters( const std::string& eid, const std::string& cid, const std::vector& scopes_arg, + const std::string& device_id, Mode mode_arg) - : extension_id(eid), client_id(cid), scopes(scopes_arg), mode(mode_arg) { + : extension_id(eid), + client_id(cid), + scopes(scopes_arg), + device_id(device_id), + mode(mode_arg) { } OAuth2MintTokenFlow::Parameters::~Parameters() {} @@ -151,7 +158,7 @@ std::string OAuth2MintTokenFlow::CreateApiCallBody() { (parameters_.mode == MODE_MINT_TOKEN_NO_FORCE || parameters_.mode == MODE_MINT_TOKEN_FORCE) ? kResponseTypeValueToken : kResponseTypeValueNone; - return base::StringPrintf( + std::string body = base::StringPrintf( kOAuth2IssueTokenBodyFormat, net::EscapeUrlEncodedData(force_value, true).c_str(), net::EscapeUrlEncodedData(response_type_value, true).c_str(), @@ -159,6 +166,12 @@ std::string OAuth2MintTokenFlow::CreateApiCallBody() { JoinString(parameters_.scopes, ' '), true).c_str(), net::EscapeUrlEncodedData(parameters_.client_id, true).c_str(), net::EscapeUrlEncodedData(parameters_.extension_id, true).c_str()); + if (!parameters_.device_id.empty()) { + body.append(base::StringPrintf( + kOAuth2IssueTokenBodyFormatDeviceIdAddendum, + net::EscapeUrlEncodedData(parameters_.device_id, true).c_str())); + } + return body; } void OAuth2MintTokenFlow::ProcessApiCallSuccess( diff --git a/google_apis/gaia/oauth2_mint_token_flow.h b/google_apis/gaia/oauth2_mint_token_flow.h index 1f4180d222613..9fe3b88e7dcac 100644 --- a/google_apis/gaia/oauth2_mint_token_flow.h +++ b/google_apis/gaia/oauth2_mint_token_flow.h @@ -58,7 +58,7 @@ typedef std::vector IssueAdviceInfo; // scoped "master" OAuth2 token for the user logged in to Chrome. class OAuth2MintTokenFlow : public OAuth2ApiCallFlow { public: - // There are four differnt modes when minting a token to grant + // There are four different modes when minting a token to grant // access to third-party app for a user. enum Mode { // Get the messages to display to the user without minting a token. @@ -78,12 +78,14 @@ class OAuth2MintTokenFlow : public OAuth2ApiCallFlow { Parameters(const std::string& eid, const std::string& cid, const std::vector& scopes_arg, + const std::string& device_id, Mode mode_arg); ~Parameters(); std::string extension_id; std::string client_id; std::vector scopes; + std::string device_id; Mode mode; }; diff --git a/google_apis/gaia/oauth2_mint_token_flow_unittest.cc b/google_apis/gaia/oauth2_mint_token_flow_unittest.cc index cd5508e70fac0..c60ad31c948f1 100644 --- a/google_apis/gaia/oauth2_mint_token_flow_unittest.cc +++ b/google_apis/gaia/oauth2_mint_token_flow_unittest.cc @@ -154,17 +154,23 @@ class OAuth2MintTokenFlowTest : public testing::Test { protected: void CreateFlow(OAuth2MintTokenFlow::Mode mode) { - return CreateFlow(&delegate_, mode); + return CreateFlow(&delegate_, mode, ""); + } + + void CreateFlowWithDeviceId(const std::string& device_id) { + return CreateFlow(&delegate_, OAuth2MintTokenFlow::MODE_ISSUE_ADVICE, + device_id); } void CreateFlow(MockDelegate* delegate, - OAuth2MintTokenFlow::Mode mode) { + OAuth2MintTokenFlow::Mode mode, + const std::string& device_id) { std::string ext_id = "ext1"; std::string client_id = "client1"; std::vector scopes(CreateTestScopes()); flow_.reset(new MockMintTokenFlow( - delegate, - OAuth2MintTokenFlow::Parameters(ext_id, client_id, scopes, mode))); + delegate, OAuth2MintTokenFlow::Parameters(ext_id, client_id, scopes, + device_id, mode))); } // Helper to parse the given string to DictionaryValue. @@ -184,11 +190,11 @@ TEST_F(OAuth2MintTokenFlowTest, CreateApiCallBody) { CreateFlow(OAuth2MintTokenFlow::MODE_ISSUE_ADVICE); std::string body = flow_->CreateApiCallBody(); std::string expected_body( - "force=false" - "&response_type=none" - "&scope=http://scope1+http://scope2" - "&client_id=client1" - "&origin=ext1"); + "force=false" + "&response_type=none" + "&scope=http://scope1+http://scope2" + "&client_id=client1" + "&origin=ext1"); EXPECT_EQ(expected_body, body); } { // Record grant mode. @@ -224,6 +230,19 @@ TEST_F(OAuth2MintTokenFlowTest, CreateApiCallBody) { "&origin=ext1"); EXPECT_EQ(expected_body, body); } + { // Mint token with device_id. + CreateFlowWithDeviceId("device_id1"); + std::string body = flow_->CreateApiCallBody(); + std::string expected_body( + "force=false" + "&response_type=none" + "&scope=http://scope1+http://scope2" + "&client_id=client1" + "&origin=ext1" + "&device_id=device_id1" + "&device_type=chrome"); + EXPECT_EQ(expected_body, body); + } } TEST_F(OAuth2MintTokenFlowTest, ParseMintTokenResponse) { @@ -332,7 +351,7 @@ TEST_F(OAuth2MintTokenFlowTest, ProcessApiCallFailure) { { // Null delegate should work fine. TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL); url_fetcher.set_status(URLRequestStatus(URLRequestStatus::FAILED, 101)); - CreateFlow(NULL, OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE); + CreateFlow(NULL, OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE, ""); flow_->ProcessApiCallFailure(&url_fetcher); } diff --git a/google_apis/gcm/engine/account_mapping.cc b/google_apis/gcm/engine/account_mapping.cc index e1540779b0233..db7b3a10dcdb7 100644 --- a/google_apis/gcm/engine/account_mapping.cc +++ b/google_apis/gcm/engine/account_mapping.cc @@ -100,10 +100,8 @@ bool AccountMapping::ParseFromString(const std::string& value) { if (!StringToStatus(values[kStatusIndex], &temp_status)) return false; - if (values.size() == kSizeWithNoMessage && - (temp_status == REMOVING || temp_status == ADDING)) { + if (values.size() == kSizeWithNoMessage && temp_status == ADDING) return false; - } int64 status_change_ts_internal = 0LL; if (!base::StringToInt64(values[kStatusChangeTimestampIndex], diff --git a/google_apis/gcm/engine/account_mapping_unittest.cc b/google_apis/gcm/engine/account_mapping_unittest.cc index 5ce5d0544b398..f4764f1544d45 100644 --- a/google_apis/gcm/engine/account_mapping_unittest.cc +++ b/google_apis/gcm/engine/account_mapping_unittest.cc @@ -45,6 +45,12 @@ TEST(AccountMappingTest, SerializeAccountMapping) { account_mapping.email = "test@gmail.com"; account_mapping.access_token = "access_token"; // should be ignored. account_mapping.status = AccountMapping::REMOVING; + + // Serialize removing message without a message_id. + EXPECT_EQ("test@gmail.com&removing&1305797421259977", + account_mapping.SerializeAsString()); + + // Add a message ID and serialize again. account_mapping.last_message_id = "last_message_id_2"; EXPECT_EQ("test@gmail.com&removing&1305797421259977&last_message_id_2", @@ -102,6 +108,16 @@ TEST(AccountMappingTest, DeserializeAccountMapping) { EXPECT_EQ(base::Time::FromInternalValue(1305797421259977LL), account_mapping.status_change_timestamp); EXPECT_EQ("last_message_id_2", account_mapping.last_message_id); + + EXPECT_TRUE(account_mapping.ParseFromString( + "test@gmail.com&removing&1305797421259935")); + EXPECT_EQ("acc_id", account_mapping.account_id); + EXPECT_EQ("test@gmail.com", account_mapping.email); + EXPECT_TRUE(account_mapping.access_token.empty()); + EXPECT_EQ(AccountMapping::REMOVING, account_mapping.status); + EXPECT_EQ(base::Time::FromInternalValue(1305797421259935LL), + account_mapping.status_change_timestamp); + EXPECT_TRUE(account_mapping.last_message_id.empty()); } TEST(AccountMappingTest, DeserializeAccountMappingInvalidInput) { @@ -111,9 +127,6 @@ TEST(AccountMappingTest, DeserializeAccountMappingInvalidInput) { EXPECT_FALSE(account_mapping.ParseFromString( "test@example.com&adding&1305797421259935&last_message_id_1&stuff_here")); // Too few arguments. - EXPECT_FALSE(account_mapping.ParseFromString( - "test@example.com&removing&1305797421259935")); - // Too few arguments. EXPECT_FALSE(account_mapping.ParseFromString( "test@example.com&adding&1305797421259935")); // Too few arguments. @@ -137,9 +150,6 @@ TEST(AccountMappingTest, DeserializeAccountMappingInvalidInput) { // Last mapping status change timestamp not parseable. EXPECT_FALSE(account_mapping.ParseFromString( "test@gmail.com&removing&asdfjkl&last_message_id_2")); - // Missing last message ID. - EXPECT_FALSE(account_mapping.ParseFromString( - "test@example.com&removing&1305797421259935&")); } } // namespace diff --git a/google_apis/gcm/engine/gcm_store_impl.cc b/google_apis/gcm/engine/gcm_store_impl.cc index 25bc8474fbcb2..14e382e61980a 100644 --- a/google_apis/gcm/engine/gcm_store_impl.cc +++ b/google_apis/gcm/engine/gcm_store_impl.cc @@ -552,11 +552,11 @@ void GCMStoreImpl::Backend::SetGServicesSettings( // Remove all existing settings. leveldb::ReadOptions read_options; read_options.verify_checksums = true; - scoped_ptr db_iter(db_->NewIterator(read_options)); - for (db_iter->Seek(MakeSlice(kGServiceSettingKeyStart)); - db_iter->Valid() && db_iter->key().ToString() < kGServiceSettingKeyEnd; - db_iter->Next()) { - write_batch.Delete(db_iter->key()); + scoped_ptr iter(db_->NewIterator(read_options)); + for (iter->Seek(MakeSlice(kGServiceSettingKeyStart)); + iter->Valid() && iter->key().ToString() < kGServiceSettingKeyEnd; + iter->Next()) { + write_batch.Delete(iter->key()); } // Add the new settings. diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index 241056cefd013..de53a6e1f4a93 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc @@ -296,8 +296,11 @@ GLES2Implementation::~GLES2Implementation() { WaitForCmd(); query_tracker_.reset(); - if (support_client_side_arrays_) + // GLES2Implementation::Initialize() could fail before allocating + // reserved_ids_, so we need delete them carefully. + if (support_client_side_arrays_ && reserved_ids_[0]) { DeleteBuffers(arraysize(reserved_ids_), &reserved_ids_[0]); + } // Release any per-context data in share group. share_group_->FreeContext(this); diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc index 799618cb4d795..a004e3873fd60 100644 --- a/gpu/command_buffer/client/gles2_implementation_unittest.cc +++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc @@ -93,7 +93,8 @@ class MockTransferBuffer : public TransferBufferInterface { CommandBuffer* command_buffer, unsigned int size, unsigned int result_size, - unsigned int alignment) + unsigned int alignment, + bool initialize_fail) : command_buffer_(command_buffer), size_(size), result_size_(result_size), @@ -102,7 +103,8 @@ class MockTransferBuffer : public TransferBufferInterface { expected_buffer_index_(0), last_alloc_(NULL), expected_offset_(result_size), - actual_offset_(result_size) { + actual_offset_(result_size), + initialize_fail_(initialize_fail) { // We have to allocate the buffers here because // we need to know their address before GLES2Implementation::Initialize // is called. @@ -220,6 +222,7 @@ class MockTransferBuffer : public TransferBufferInterface { void* last_alloc_; uint32 expected_offset_; uint32 actual_offset_; + bool initialize_fail_; DISALLOW_COPY_AND_ASSIGN(MockTransferBuffer); }; @@ -234,7 +237,7 @@ bool MockTransferBuffer::Initialize( // Just check they match. return size_ == starting_buffer_size && result_size_ == result_size && - alignment_ == alignment; + alignment_ == alignment && !initialize_fail_; }; int MockTransferBuffer::GetShmId() { @@ -394,7 +397,8 @@ class GLES2ImplementationTest : public testing::Test { bool Initialize(ShareGroup* share_group, bool bind_generates_resource_client, bool bind_generates_resource_service, - bool lose_context_when_out_of_memory) { + bool lose_context_when_out_of_memory, + bool transfer_buffer_initialize_fail) { command_buffer_.reset(new StrictMock()); if (!command_buffer_->Initialize()) return false; @@ -403,7 +407,8 @@ class GLES2ImplementationTest : public testing::Test { new MockTransferBuffer(command_buffer_.get(), kTransferBufferSize, GLES2Implementation::kStartingOffset, - GLES2Implementation::kAlignment)); + GLES2Implementation::kAlignment, + transfer_buffer_initialize_fail)); helper_.reset(new GLES2CmdHelper(command_buffer())); helper_->Initialize(kCommandBufferSizeBytes); @@ -530,11 +535,13 @@ class GLES2ImplementationTest : public testing::Test { ContextInitOptions() : bind_generates_resource_client(true), bind_generates_resource_service(true), - lose_context_when_out_of_memory(false) {} + lose_context_when_out_of_memory(false), + transfer_buffer_initialize_fail(false) {} bool bind_generates_resource_client; bool bind_generates_resource_service; bool lose_context_when_out_of_memory; + bool transfer_buffer_initialize_fail; }; bool Initialize(const ContextInitOptions& init_options) { @@ -546,7 +553,8 @@ class GLES2ImplementationTest : public testing::Test { share_group_.get(), init_options.bind_generates_resource_client, init_options.bind_generates_resource_service, - init_options.lose_context_when_out_of_memory)) + init_options.lose_context_when_out_of_memory, + init_options.transfer_buffer_initialize_fail)) success = false; } @@ -3410,6 +3418,12 @@ TEST_F(GLES2ImplementationManualInitTest, FailInitOnBGRMismatch2) { EXPECT_FALSE(Initialize(init_options)); } +TEST_F(GLES2ImplementationManualInitTest, FailInitOnTransferBufferFail) { + ContextInitOptions init_options; + init_options.transfer_buffer_initialize_fail = true; + EXPECT_FALSE(Initialize(init_options)); +} + #include "gpu/command_buffer/client/gles2_implementation_unittest_autogen.h" } // namespace gles2 diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc index 9be747de433a2..b06292abfa313 100644 --- a/gpu/command_buffer/service/feature_info.cc +++ b/gpu/command_buffer/service/feature_info.cc @@ -842,6 +842,9 @@ void FeatureInfo::InitializeFeatures() { if (workarounds_.disable_egl_khr_fence_sync) { gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync = false; } + if (workarounds_.disable_egl_khr_wait_sync) { + gfx::g_driver_egl.ext.b_EGL_KHR_wait_sync = false; + } #endif if (workarounds_.disable_arb_sync) gfx::g_driver_gl.ext.b_GL_ARB_sync = false; diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 6905d2af0c18d..8577d820d15a8 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -628,7 +628,7 @@ class GLES2DecoderImpl : public GLES2Decoder, return vertex_array_manager_.get(); } ImageManager* GetImageManager() override { return image_manager_.get(); } - bool ProcessPendingQueries() override; + bool ProcessPendingQueries(bool did_finish) override; bool HasMoreIdleWork() override; void PerformIdleWork() override; @@ -3998,12 +3998,12 @@ bool GLES2DecoderImpl::CreateShaderHelper(GLenum type, GLuint client_id) { void GLES2DecoderImpl::DoFinish() { glFinish(); ProcessPendingReadPixels(); - ProcessPendingQueries(); + ProcessPendingQueries(true); } void GLES2DecoderImpl::DoFlush() { glFlush(); - ProcessPendingQueries(); + ProcessPendingQueries(false); } void GLES2DecoderImpl::DoActiveTexture(GLenum texture_unit) { @@ -9957,11 +9957,11 @@ void GLES2DecoderImpl::DeleteQueriesEXTHelper( } } -bool GLES2DecoderImpl::ProcessPendingQueries() { +bool GLES2DecoderImpl::ProcessPendingQueries(bool did_finish) { if (query_manager_.get() == NULL) { return false; } - if (!query_manager_->ProcessPendingQueries()) { + if (!query_manager_->ProcessPendingQueries(did_finish)) { current_decoder_error_ = error::kOutOfBounds; } return query_manager_->HavePendingQueries(); diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h index 8d72335f7febf..63618c2a2da03 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder.h @@ -171,7 +171,7 @@ class GPU_EXPORT GLES2Decoder : public base::SupportsWeakPtr, virtual ImageManager* GetImageManager() = 0; // Process any pending queries. Returns false if there are no pending queries. - virtual bool ProcessPendingQueries() = 0; + virtual bool ProcessPendingQueries(bool did_finish) = 0; // Returns false if there are no idle work to be made. virtual bool HasMoreIdleWork() = 0; diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h index 7346d8e632c2c..d855c87483b0a 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h @@ -57,7 +57,7 @@ class MockGLES2Decoder : public GLES2Decoder { MOCK_METHOD0(GetContextGroup, ContextGroup*()); MOCK_METHOD0(GetContextState, const ContextState*()); MOCK_METHOD0(GetCapabilities, Capabilities()); - MOCK_METHOD0(ProcessPendingQueries, bool()); + MOCK_METHOD1(ProcessPendingQueries, bool(bool)); MOCK_METHOD0(HasMoreIdleWork, bool()); MOCK_METHOD0(PerformIdleWork, void()); MOCK_METHOD1(RestoreState, void(const ContextState* prev_state)); diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc index e97b4c4eb95ef..43f8606396296 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc @@ -636,7 +636,7 @@ static void CheckBeginEndQueryBadMemoryFails(GLES2DecoderTestBase* test, QueryManager* query_manager = test->GetDecoder()->GetQueryManager(); ASSERT_TRUE(query_manager != NULL); - bool process_success = query_manager->ProcessPendingQueries(); + bool process_success = query_manager->ProcessPendingQueries(false); EXPECT_TRUE(error1 != error::kNoError || error2 != error::kNoError || !process_success); @@ -797,7 +797,7 @@ TEST_P(GLES2DecoderManualInitTest, BeginEndQueryEXTCommandsCompletedCHROMIUM) { EXPECT_CALL(*gl_, ClientWaitSync(kGlSync, _, _)) .WillOnce(Return(GL_TIMEOUT_EXPIRED)) .RetiresOnSaturation(); - bool process_success = query_manager->ProcessPendingQueries(); + bool process_success = query_manager->ProcessPendingQueries(false); EXPECT_TRUE(process_success); EXPECT_TRUE(query->pending()); @@ -810,7 +810,7 @@ TEST_P(GLES2DecoderManualInitTest, BeginEndQueryEXTCommandsCompletedCHROMIUM) { EXPECT_CALL(*gl_, ClientWaitSync(kGlSync, _, _)) .WillOnce(Return(GL_ALREADY_SIGNALED)) .RetiresOnSaturation(); - process_success = query_manager->ProcessPendingQueries(); + process_success = query_manager->ProcessPendingQueries(false); EXPECT_TRUE(process_success); EXPECT_FALSE(query->pending()); diff --git a/gpu/command_buffer/service/gpu_scheduler.cc b/gpu/command_buffer/service/gpu_scheduler.cc index 058a546d8578d..48df8dd98c48d 100644 --- a/gpu/command_buffer/service/gpu_scheduler.cc +++ b/gpu/command_buffer/service/gpu_scheduler.cc @@ -170,7 +170,7 @@ bool GpuScheduler::IsScheduled() { bool GpuScheduler::HasMoreWork() { return !unschedule_fences_.empty() || - (decoder_ && decoder_->ProcessPendingQueries()) || + (decoder_ && decoder_->ProcessPendingQueries(false)) || HasMoreIdleWork(); } diff --git a/gpu/command_buffer/service/query_manager.cc b/gpu/command_buffer/service/query_manager.cc index 5f518eca4c24c..fdb5fa82f27fb 100644 --- a/gpu/command_buffer/service/query_manager.cc +++ b/gpu/command_buffer/service/query_manager.cc @@ -64,7 +64,7 @@ class AsyncPixelTransfersCompletedQuery bool Begin() override; bool End(base::subtle::Atomic32 submit_count) override; - bool Process() override; + bool Process(bool did_finish) override; void Destroy(bool have_context) override; protected: @@ -105,7 +105,7 @@ bool AsyncPixelTransfersCompletedQuery::End( return AddToPendingTransferQueue(submit_count); } -bool AsyncPixelTransfersCompletedQuery::Process() { +bool AsyncPixelTransfersCompletedQuery::Process(bool did_finish) { QuerySync* sync = manager()->decoder()->GetSharedMemoryAs( shm_id(), shm_offset(), sizeof(*sync)); if (!sync) @@ -141,7 +141,7 @@ class AllSamplesPassedQuery : public QueryManager::Query { GLuint service_id); bool Begin() override; bool End(base::subtle::Atomic32 submit_count) override; - bool Process() override; + bool Process(bool did_finish) override; void Destroy(bool have_context) override; protected: @@ -169,7 +169,7 @@ bool AllSamplesPassedQuery::End(base::subtle::Atomic32 submit_count) { return AddToPendingQueue(submit_count); } -bool AllSamplesPassedQuery::Process() { +bool AllSamplesPassedQuery::Process(bool did_finish) { GLuint available = 0; glGetQueryObjectuivARB( service_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available); @@ -200,7 +200,7 @@ class CommandsIssuedQuery : public QueryManager::Query { bool Begin() override; bool End(base::subtle::Atomic32 submit_count) override; - bool Process() override; + bool Process(bool did_finish) override; void Destroy(bool have_context) override; protected: @@ -226,7 +226,7 @@ bool CommandsIssuedQuery::End(base::subtle::Atomic32 submit_count) { return MarkAsCompleted(elapsed.InMicroseconds()); } -bool CommandsIssuedQuery::Process() { +bool CommandsIssuedQuery::Process(bool did_finish) { NOTREACHED(); return true; } @@ -247,7 +247,7 @@ class CommandLatencyQuery : public QueryManager::Query { bool Begin() override; bool End(base::subtle::Atomic32 submit_count) override; - bool Process() override; + bool Process(bool did_finish) override; void Destroy(bool have_context) override; protected: @@ -269,7 +269,7 @@ bool CommandLatencyQuery::End(base::subtle::Atomic32 submit_count) { return MarkAsCompleted(now.InMicroseconds()); } -bool CommandLatencyQuery::Process() { +bool CommandLatencyQuery::Process(bool did_finish) { NOTREACHED(); return true; } @@ -293,7 +293,7 @@ class AsyncReadPixelsCompletedQuery bool Begin() override; bool End(base::subtle::Atomic32 submit_count) override; - bool Process() override; + bool Process(bool did_finish) override; void Destroy(bool have_context) override; protected: @@ -324,7 +324,7 @@ bool AsyncReadPixelsCompletedQuery::End(base::subtle::Atomic32 submit_count) { base::Bind(&AsyncReadPixelsCompletedQuery::Complete, AsWeakPtr())); - return Process(); + return Process(false); } void AsyncReadPixelsCompletedQuery::Complete() { @@ -332,7 +332,7 @@ void AsyncReadPixelsCompletedQuery::Complete() { complete_result_ = MarkAsCompleted(1); } -bool AsyncReadPixelsCompletedQuery::Process() { +bool AsyncReadPixelsCompletedQuery::Process(bool did_finish) { return !completed_ || complete_result_; } @@ -353,7 +353,7 @@ class GetErrorQuery : public QueryManager::Query { bool Begin() override; bool End(base::subtle::Atomic32 submit_count) override; - bool Process() override; + bool Process(bool did_finish) override; void Destroy(bool have_context) override; protected: @@ -376,7 +376,7 @@ bool GetErrorQuery::End(base::subtle::Atomic32 submit_count) { return MarkAsCompleted(manager()->decoder()->GetErrorState()->GetGLError()); } -bool GetErrorQuery::Process() { +bool GetErrorQuery::Process(bool did_finish) { NOTREACHED(); return true; } @@ -400,7 +400,7 @@ class CommandsCompletedQuery : public QueryManager::Query { // Overridden from QueryManager::Query: bool Begin() override; bool End(base::subtle::Atomic32 submit_count) override; - bool Process() override; + bool Process(bool did_finish) override; void Destroy(bool have_context) override; protected: @@ -424,9 +424,16 @@ bool CommandsCompletedQuery::End(base::subtle::Atomic32 submit_count) { return AddToPendingQueue(submit_count); } -bool CommandsCompletedQuery::Process() { - if (fence_ && !fence_->HasCompleted()) +bool CommandsCompletedQuery::Process(bool did_finish) { + // Note: |did_finish| guarantees that the GPU has passed the fence but + // we cannot assume that GLFence::HasCompleted() will return true yet as + // that's not guaranteed by all GLFence implementations. + // + // TODO(reveman): Add UMA stats to determine how common it is that glFinish() + // needs to be called for these queries to complete. crbug.com/431845 + if (!did_finish && fence_ && !fence_->HasCompleted()) return true; + return MarkAsCompleted(0); } @@ -635,10 +642,10 @@ bool QueryManager::Query::MarkAsCompleted(uint64 result) { return true; } -bool QueryManager::ProcessPendingQueries() { +bool QueryManager::ProcessPendingQueries(bool did_finish) { while (!pending_queries_.empty()) { Query* query = pending_queries_.front().get(); - if (!query->Process()) { + if (!query->Process(did_finish)) { return false; } if (query->pending()) { @@ -658,7 +665,7 @@ bool QueryManager::HavePendingQueries() { bool QueryManager::ProcessPendingTransferQueries() { while (!pending_transfer_queries_.empty()) { Query* query = pending_transfer_queries_.front().get(); - if (!query->Process()) { + if (!query->Process(false)) { return false; } if (query->pending()) { diff --git a/gpu/command_buffer/service/query_manager.h b/gpu/command_buffer/service/query_manager.h index 62da3b8672feb..5f14929272c2c 100644 --- a/gpu/command_buffer/service/query_manager.h +++ b/gpu/command_buffer/service/query_manager.h @@ -64,7 +64,7 @@ class GPU_EXPORT QueryManager { virtual bool End(base::subtle::Atomic32 submit_count) = 0; // Returns false if shared memory for sync is invalid. - virtual bool Process() = 0; + virtual bool Process(bool did_finish) = 0; virtual void Destroy(bool have_context) = 0; @@ -170,8 +170,9 @@ class GPU_EXPORT QueryManager { bool EndQuery(Query* query, base::subtle::Atomic32 submit_count); // Processes pending queries. Returns false if any queries are pointing - // to invalid shared memory. - bool ProcessPendingQueries(); + // to invalid shared memory. |did_finish| is true if this is called as + // a result of calling glFinish(). + bool ProcessPendingQueries(bool did_finish); // True if there are pending queries. bool HavePendingQueries(); diff --git a/gpu/command_buffer/service/query_manager_unittest.cc b/gpu/command_buffer/service/query_manager_unittest.cc index 80efd69e0ad3a..7c8e93cbc193a 100644 --- a/gpu/command_buffer/service/query_manager_unittest.cc +++ b/gpu/command_buffer/service/query_manager_unittest.cc @@ -214,7 +214,7 @@ TEST_F(QueryManagerTest, ProcessPendingQuery) { const GLuint kResult = 1; // Check nothing happens if there are no pending queries. - EXPECT_TRUE(manager_->ProcessPendingQueries()); + EXPECT_TRUE(manager_->ProcessPendingQueries(false)); // Create Query. scoped_refptr query( @@ -239,7 +239,7 @@ TEST_F(QueryManagerTest, ProcessPendingQuery) { GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_AVAILABLE_EXT, _)) .WillOnce(SetArgumentPointee<2>(0)) .RetiresOnSaturation(); - EXPECT_TRUE(manager_->ProcessPendingQueries()); + EXPECT_TRUE(manager_->ProcessPendingQueries(false)); EXPECT_TRUE(query->pending()); EXPECT_EQ(0, sync->process_count); EXPECT_EQ(0u, sync->result); @@ -254,7 +254,7 @@ TEST_F(QueryManagerTest, ProcessPendingQuery) { GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_EXT, _)) .WillOnce(SetArgumentPointee<2>(kResult)) .RetiresOnSaturation(); - EXPECT_TRUE(manager_->ProcessPendingQueries()); + EXPECT_TRUE(manager_->ProcessPendingQueries(false)); EXPECT_FALSE(query->pending()); EXPECT_EQ(kSubmitCount, sync->process_count); EXPECT_EQ(kResult, sync->result); @@ -262,7 +262,7 @@ TEST_F(QueryManagerTest, ProcessPendingQuery) { // Process with no queries. // Expect no GL commands/ - EXPECT_TRUE(manager_->ProcessPendingQueries()); + EXPECT_TRUE(manager_->ProcessPendingQueries(false)); } TEST_F(QueryManagerTest, ProcessPendingQueries) { @@ -342,7 +342,7 @@ TEST_F(QueryManagerTest, ProcessPendingQueries) { GetQueryObjectuivARB(kService3Id, GL_QUERY_RESULT_AVAILABLE_EXT, _)) .WillOnce(SetArgumentPointee<2>(0)) .RetiresOnSaturation(); - EXPECT_TRUE(manager_->ProcessPendingQueries()); + EXPECT_TRUE(manager_->ProcessPendingQueries(false)); } EXPECT_FALSE(query1->pending()); EXPECT_FALSE(query2->pending()); @@ -361,7 +361,7 @@ TEST_F(QueryManagerTest, ProcessPendingQueries) { GetQueryObjectuivARB(kService3Id, GL_QUERY_RESULT_AVAILABLE_EXT, _)) .WillOnce(SetArgumentPointee<2>(0)) .RetiresOnSaturation(); - EXPECT_TRUE(manager_->ProcessPendingQueries()); + EXPECT_TRUE(manager_->ProcessPendingQueries(false)); EXPECT_TRUE(query3->pending()); EXPECT_EQ(0, sync3->process_count); EXPECT_EQ(0u, sync3->result); @@ -377,7 +377,7 @@ TEST_F(QueryManagerTest, ProcessPendingQueries) { GetQueryObjectuivARB(kService3Id, GL_QUERY_RESULT_EXT, _)) .WillOnce(SetArgumentPointee<2>(kResult3)) .RetiresOnSaturation(); - EXPECT_TRUE(manager_->ProcessPendingQueries()); + EXPECT_TRUE(manager_->ProcessPendingQueries(false)); EXPECT_FALSE(query3->pending()); EXPECT_EQ(kSubmitCount3, sync3->process_count); EXPECT_EQ(kResult3, sync3->result); @@ -410,7 +410,7 @@ TEST_F(QueryManagerTest, ProcessPendingBadSharedMemoryId) { GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_EXT, _)) .WillOnce(SetArgumentPointee<2>(kResult)) .RetiresOnSaturation(); - EXPECT_FALSE(manager_->ProcessPendingQueries()); + EXPECT_FALSE(manager_->ProcessPendingQueries(false)); } TEST_F(QueryManagerTest, ProcessPendingBadSharedMemoryOffset) { @@ -439,7 +439,7 @@ TEST_F(QueryManagerTest, ProcessPendingBadSharedMemoryOffset) { GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_EXT, _)) .WillOnce(SetArgumentPointee<2>(kResult)) .RetiresOnSaturation(); - EXPECT_FALSE(manager_->ProcessPendingQueries()); + EXPECT_FALSE(manager_->ProcessPendingQueries(false)); } TEST_F(QueryManagerTest, ExitWithPendingQuery) { diff --git a/gpu/config/gpu_driver_bug_list_json.cc b/gpu/config/gpu_driver_bug_list_json.cc index c9b5335d16157..e1e9650dbd364 100644 --- a/gpu/config/gpu_driver_bug_list_json.cc +++ b/gpu/config/gpu_driver_bug_list_json.cc @@ -19,7 +19,7 @@ const char kGpuDriverBugListJson[] = LONG_STRING_CONST( { "name": "gpu driver bug list", // Please update the version number whenever you change this file. - "version": "7.7", + "version": "7.8", "entries": [ { "id": 1, @@ -1046,6 +1046,27 @@ LONG_STRING_CONST( "features": [ "disable_async_readpixels" ] + }, + { + "id": 94, + "description": "Disable EGL_KHR_wait_sync on NVIDIA with GLES 3.1", + "cr_bugs": [433057], + "os": { + "type": "android", + "version": { + "op": "<=", + "value": "5.0.0" + } + }, + "gl_vendor": "NVIDIA.*", + "gl_type": "gles", + "gl_version": { + "op": "=", + "value": "3.1" + }, + "features": [ + "disable_egl_khr_wait_sync" + ] } ] } diff --git a/gpu/config/gpu_driver_bug_workaround_type.h b/gpu/config/gpu_driver_bug_workaround_type.h index 871798ed18e44..0cd97610dc79f 100644 --- a/gpu/config/gpu_driver_bug_workaround_type.h +++ b/gpu/config/gpu_driver_bug_workaround_type.h @@ -28,6 +28,8 @@ disable_depth_texture) \ GPU_OP(DISABLE_EGL_KHR_FENCE_SYNC, \ disable_egl_khr_fence_sync) \ + GPU_OP(DISABLE_EGL_KHR_WAIT_SYNC, \ + disable_egl_khr_wait_sync) \ GPU_OP(DISABLE_EXT_DISCARD_FRAMEBUFFER, \ disable_ext_discard_framebuffer) \ GPU_OP(DISABLE_EXT_DRAW_BUFFERS, \ diff --git a/media/audio/android/audio_manager_android.cc b/media/audio/android/audio_manager_android.cc index 68dae3a4cce91..cf28a1e5a9832 100644 --- a/media/audio/android/audio_manager_android.cc +++ b/media/audio/android/audio_manager_android.cc @@ -4,6 +4,9 @@ #include "media/audio/android/audio_manager_android.h" +#include +#include + #include "base/android/build_info.h" #include "base/android/jni_array.h" #include "base/android/jni_string.h" @@ -247,8 +250,19 @@ AudioInputStream* AudioManagerAndroid::MakeLowLatencyInputStream( DVLOG(1) << "Creating AudioRecordInputStream"; return new AudioRecordInputStream(this, params); } + + // TODO(xingnan): Crash will happen in the openSL ES library on some IA + // devices like ZTE Geek V975, Use AudioRecordInputStream path instead as + // a workaround. Will fall back after the fix of the bug. +#if defined(ARCH_CPU_X86) + if (base::android::BuildInfo::GetInstance()->sdk_int() < 16) + return NULL; + DVLOG(1) << "Creating AudioRecordInputStream"; + return new AudioRecordInputStream(this, params); +#else DVLOG(1) << "Creating OpenSLESInputStream"; return new OpenSLESInputStream(this, params); +#endif } // static diff --git a/media/audio/audio_io.h b/media/audio/audio_io.h index 3add053952c53..4c6ca3c66e667 100644 --- a/media/audio/audio_io.h +++ b/media/audio/audio_io.h @@ -5,6 +5,10 @@ #ifndef MEDIA_AUDIO_AUDIO_IO_H_ #define MEDIA_AUDIO_AUDIO_IO_H_ +#if defined(OS_TIZEN) +#include +#endif + #include "base/basictypes.h" #include "media/base/audio_bus.h" @@ -97,6 +101,13 @@ class MEDIA_EXPORT AudioOutputStream { // Close the stream. This also generates AudioSourceCallback::OnClose(). // After calling this method, the object should not be used anymore. virtual void Close() = 0; + +#if defined(OS_TIZEN) + // Sets an application ID and class properties, which are used to tag audio + // streams in pulseaudio/Murphy. + virtual void SetMediaStreamProperties(const std::string& app_id, + const std::string& app_class) {} +#endif }; // Models an audio sink receiving recorded audio from the audio driver. diff --git a/media/audio/audio_output_controller.cc b/media/audio/audio_output_controller.cc index a38bc526f2926..140ef77179bab 100644 --- a/media/audio/audio_output_controller.cc +++ b/media/audio/audio_output_controller.cc @@ -128,6 +128,10 @@ void AudioOutputController::DoCreate(bool is_for_device_change) { return; } +#if defined(OS_TIZEN) + stream_->SetMediaStreamProperties(handler_->app_id(), handler_->app_class()); +#endif + if (!stream_->Open()) { DoStopCloseAndClearStream(); state_ = kError; diff --git a/media/audio/audio_output_controller.h b/media/audio/audio_output_controller.h index 23dc897d6ef3b..2f5cdf85190da 100644 --- a/media/audio/audio_output_controller.h +++ b/media/audio/audio_output_controller.h @@ -5,6 +5,10 @@ #ifndef MEDIA_AUDIO_AUDIO_OUTPUT_CONTROLLER_H_ #define MEDIA_AUDIO_AUDIO_OUTPUT_CONTROLLER_H_ +#if defined(OS_TIZEN) +#include +#endif + #include "base/atomic_ref_count.h" #include "base/callback.h" #include "base/memory/ref_counted.h" @@ -69,6 +73,11 @@ class MEDIA_EXPORT AudioOutputController virtual void OnError() = 0; virtual void OnDeviceChange(int new_buffer_size, int new_sample_rate) = 0; +#if defined(OS_TIZEN) + virtual std::string app_id() const = 0; + virtual std::string app_class() const = 0; +#endif + protected: virtual ~EventHandler() {} }; diff --git a/media/audio/audio_output_dispatcher.cc b/media/audio/audio_output_dispatcher.cc index a03ae6e083ee2..92a3729be1146 100644 --- a/media/audio/audio_output_dispatcher.cc +++ b/media/audio/audio_output_dispatcher.cc @@ -26,4 +26,13 @@ AudioOutputDispatcher::~AudioOutputDispatcher() { DCHECK(task_runner_->BelongsToCurrentThread()); } +#if defined(OS_TIZEN) +void AudioOutputDispatcher::SetMediaStreamProperties( + const std::string& app_id, + const std::string& app_class) { + app_id_ = app_id; + app_class_ = app_class; +} +#endif + } // namespace media diff --git a/media/audio/audio_output_dispatcher.h b/media/audio/audio_output_dispatcher.h index 59521c7017f8e..2c233b5a55fa6 100644 --- a/media/audio/audio_output_dispatcher.h +++ b/media/audio/audio_output_dispatcher.h @@ -18,6 +18,10 @@ #ifndef MEDIA_AUDIO_AUDIO_OUTPUT_DISPATCHER_H_ #define MEDIA_AUDIO_AUDIO_OUTPUT_DISPATCHER_H_ +#if defined(OS_TIZEN) +#include +#endif + #include "base/basictypes.h" #include "base/memory/ref_counted.h" #include "media/audio/audio_io.h" @@ -66,6 +70,11 @@ class MEDIA_EXPORT AudioOutputDispatcher const std::string& device_id() const { return device_id_; } +#if defined(OS_TIZEN) + virtual void SetMediaStreamProperties(const std::string& app_id, + const std::string& app_class); +#endif + protected: friend class base::RefCountedThreadSafe; virtual ~AudioOutputDispatcher(); @@ -77,6 +86,11 @@ class MEDIA_EXPORT AudioOutputDispatcher const AudioParameters params_; std::string device_id_; +#if defined(OS_TIZEN) + std::string app_id_; + std::string app_class_; +#endif + private: DISALLOW_COPY_AND_ASSIGN(AudioOutputDispatcher); }; diff --git a/media/audio/audio_output_dispatcher_impl.cc b/media/audio/audio_output_dispatcher_impl.cc index 0cb3db85cadf6..f44ae3082833c 100644 --- a/media/audio/audio_output_dispatcher_impl.cc +++ b/media/audio/audio_output_dispatcher_impl.cc @@ -137,6 +137,10 @@ bool AudioOutputDispatcherImpl::CreateAndOpenStream() { if (!stream) return false; +#if defined(OS_TIZEN) + stream->SetMediaStreamProperties(app_id_, app_class_); +#endif + if (!stream->Open()) { stream->Close(); return false; diff --git a/media/audio/audio_output_proxy.cc b/media/audio/audio_output_proxy.cc index a69cbc9522e8c..10d8751763aba 100644 --- a/media/audio/audio_output_proxy.cc +++ b/media/audio/audio_output_proxy.cc @@ -90,4 +90,11 @@ void AudioOutputProxy::Close() { delete this; } +#if defined(OS_TIZEN) +void AudioOutputProxy::SetMediaStreamProperties(const std::string& app_id, + const std::string& app_class) { + dispatcher_->SetMediaStreamProperties(app_id, app_class); +} +#endif + } // namespace media diff --git a/media/audio/audio_output_proxy.h b/media/audio/audio_output_proxy.h index 504b4efbe44a1..c7c66b84135c1 100644 --- a/media/audio/audio_output_proxy.h +++ b/media/audio/audio_output_proxy.h @@ -5,6 +5,10 @@ #ifndef MEDIA_AUDIO_AUDIO_OUTPUT_PROXY_H_ #define MEDIA_AUDIO_AUDIO_OUTPUT_PROXY_H_ +#if defined(OS_TIZEN) +#include +#endif + #include "base/basictypes.h" #include "base/compiler_specific.h" #include "base/memory/ref_counted.h" @@ -39,6 +43,11 @@ class MEDIA_EXPORT AudioOutputProxy void GetVolume(double* volume) override; void Close() override; +#if defined(OS_TIZEN) + void SetMediaStreamProperties(const std::string& app_id, + const std::string& app_class) override; +#endif + private: enum State { kCreated, diff --git a/media/audio/audio_output_resampler.cc b/media/audio/audio_output_resampler.cc index 7aa32848f3297..bdd8b21871dcd 100644 --- a/media/audio/audio_output_resampler.cc +++ b/media/audio/audio_output_resampler.cc @@ -178,6 +178,10 @@ void AudioOutputResampler::Initialize() { bool AudioOutputResampler::OpenStream() { DCHECK(task_runner_->BelongsToCurrentThread()); +#if defined(OS_TIZEN) + dispatcher_->SetMediaStreamProperties(app_id_, app_class_); +#endif + if (dispatcher_->OpenStream()) { // Only record the UMA statistic if we didn't fallback during construction // and only for the first stream we open. @@ -246,6 +250,10 @@ bool AudioOutputResampler::StartStream( resampler_callback = it->second; } +#if defined(OS_TIZEN) + dispatcher_->SetMediaStreamProperties(app_id_, app_class_); +#endif + resampler_callback->Start(callback); bool result = dispatcher_->StartStream(resampler_callback, stream_proxy); if (!result) diff --git a/media/audio/mac/audio_low_latency_input_mac.cc b/media/audio/mac/audio_low_latency_input_mac.cc index 5e1c9733a2ae5..fdd072ac3f21e 100644 --- a/media/audio/mac/audio_low_latency_input_mac.cc +++ b/media/audio/mac/audio_low_latency_input_mac.cc @@ -461,6 +461,31 @@ OSStatus AUAudioInputStream::InputProc(void* user_data, if (!audio_input) return kAudioUnitErr_InvalidElement; + // Update the |mDataByteSize| value in the audio_buffer_list() since + // |number_of_frames| can be changed on the fly. + // |mDataByteSize| needs to be exactly mapping to |number_of_frames|, + // otherwise it will put CoreAudio into bad state and results in + // AudioUnitRender() returning -50 for the new created stream. + // We have also seen kAudioUnitErr_TooManyFramesToProcess (-10874) and + // kAudioUnitErr_CannotDoInCurrentContext (-10863) as error codes. + // See crbug/428706 for details. + UInt32 new_size = number_of_frames * audio_input->format_.mBytesPerFrame; + AudioBuffer* audio_buffer = audio_input->audio_buffer_list()->mBuffers; + if (new_size != audio_buffer->mDataByteSize) { + if (new_size > audio_buffer->mDataByteSize) { + // This can happen if the device is unpluged during recording. We + // allocate enough memory here to avoid depending on how CoreAudio + // handles it. + // See See http://www.crbug.com/434681 for one example when we can enter + // this scope. + audio_input->audio_data_buffer_.reset(new uint8[new_size]); + audio_buffer->mData = audio_input->audio_data_buffer_.get(); + } + + // Update the |mDataByteSize| to match |number_of_frames|. + audio_buffer->mDataByteSize = new_size; + } + // Receive audio from the AUHAL from the output scope of the Audio Unit. OSStatus result = AudioUnitRender(audio_input->audio_unit(), flags, @@ -470,7 +495,7 @@ OSStatus AUAudioInputStream::InputProc(void* user_data, audio_input->audio_buffer_list()); if (result) { UMA_HISTOGRAM_SPARSE_SLOWLY("Media.AudioInputCbErrorMac", result); - OSSTATUS_DLOG(ERROR, result) << "AudioUnitRender() failed."; + OSSTATUS_DLOG(ERROR, result) << "AudioUnitRender() failed "; return result; } @@ -500,6 +525,21 @@ OSStatus AUAudioInputStream::Provide(UInt32 number_of_frames, if (!audio_data) return kAudioUnitErr_InvalidElement; + // Dynamically increase capacity of the FIFO to handle larger buffers from + // CoreAudio. This can happen in combination with Apple Thunderbolt Displays + // when the Display Audio is used as capture source and the cable is first + // remove and then inserted again. + // See http://www.crbug.com/434681 for details. + if (static_cast(number_of_frames) > fifo_.GetUnfilledFrames()) { + // Derive required increase in number of FIFO blocks. The increase is + // typically one block. + const int blocks = + static_cast((number_of_frames - fifo_.GetUnfilledFrames()) / + number_of_frames_) + 1; + DLOG(WARNING) << "Increasing FIFO capacity by " << blocks << " blocks"; + fifo_.IncreaseCapacity(blocks); + } + // Copy captured (and interleaved) data into FIFO. fifo_.Push(audio_data, number_of_frames, format_.mBitsPerChannel / 8); diff --git a/media/audio/pulse/pulse.sigs b/media/audio/pulse/pulse.sigs index 8d2dab70c605c..03d9aa882f168 100644 --- a/media/audio/pulse/pulse.sigs +++ b/media/audio/pulse/pulse.sigs @@ -50,3 +50,8 @@ void pa_stream_unref(pa_stream* s); int pa_context_errno(pa_context *c); const char* pa_strerror(int error); pa_cvolume* pa_cvolume_set(pa_cvolume* a, unsigned channels, pa_volume_t v); +# Functions from pulse used in TIZEN to set the audio stream role. +pa_proplist* pa_proplist_new(void); +void pa_proplist_free(pa_proplist* p); +int pa_proplist_sets(pa_proplist *p, const char *key, const char *value); +pa_stream* pa_stream_new_with_proplist(pa_context* c, const char* name, const pa_sample_spec* ss, const pa_channel_map* map, pa_proplist* proplist); diff --git a/media/audio/pulse/pulse_output.cc b/media/audio/pulse/pulse_output.cc index 1048113cf2531..27271928143a0 100644 --- a/media/audio/pulse/pulse_output.cc +++ b/media/audio/pulse/pulse_output.cc @@ -234,4 +234,13 @@ void PulseAudioOutputStream::GetVolume(double* volume) { *volume = volume_; } +#if defined(OS_TIZEN) +void PulseAudioOutputStream::SetMediaStreamProperties( + const std::string& app_id, + const std::string& app_class) { + app_id_ = app_id; + app_class_ = app_class; +} +#endif + } // namespace media diff --git a/media/audio/pulse/pulse_output.h b/media/audio/pulse/pulse_output.h index 6ec55a358f3ab..3cafc6858ea40 100644 --- a/media/audio/pulse/pulse_output.h +++ b/media/audio/pulse/pulse_output.h @@ -51,6 +51,13 @@ class PulseAudioOutputStream : public AudioOutputStream { void SetVolume(double volume) override; void GetVolume(double* volume) override; +#if defined(OS_TIZEN) + void SetMediaStreamProperties(const std::string& app_id, + const std::string& app_class) override; + const std::string& app_id() const {return app_id_;} + const std::string& app_class() const {return app_class_;} +#endif + private: // Called by PulseAudio when |pa_stream_| change state. If an unexpected // failure state change happens and |source_callback_| is set @@ -91,6 +98,12 @@ class PulseAudioOutputStream : public AudioOutputStream { // Container for retrieving data from AudioSourceCallback::OnMoreData(). scoped_ptr audio_bus_; +#if defined(OS_TIZEN) + // Application ID and class for the pulseaudio streams. + std::string app_id_; + std::string app_class_; +#endif + base::ThreadChecker thread_checker_; DISALLOW_COPY_AND_ASSIGN(PulseAudioOutputStream); diff --git a/media/audio/pulse/pulse_util.cc b/media/audio/pulse/pulse_util.cc index c06195eb19825..1cfb038308bbe 100644 --- a/media/audio/pulse/pulse_util.cc +++ b/media/audio/pulse/pulse_util.cc @@ -2,6 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#if defined(OS_TIZEN) +#include "media/audio/pulse/pulse_output.h" +#endif + #include "media/audio/pulse/pulse_util.h" #include "base/logging.h" @@ -259,7 +263,20 @@ bool CreateOutputStream(pa_threaded_mainloop** mainloop, // than the default channel map (NULL). map = &source_channel_map; } + +#if defined(OS_TIZEN) + PulseAudioOutputStream* data = + static_cast(user_data); + pa_proplist* proplist = pa_proplist_new(); + pa_proplist_sets(proplist, "resource.set.name", data->app_id().c_str()); + pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, data->app_class().c_str()); + *stream = pa_stream_new_with_proplist(*context, "Playback", + &sample_specifications, + map, proplist); + pa_proplist_free(proplist); +#else *stream = pa_stream_new(*context, "Playback", &sample_specifications, map); +#endif RETURN_ON_FAILURE(*stream, "failed to create PA playback stream"); pa_stream_set_state_callback(*stream, stream_callback, user_data); diff --git a/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java b/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java index 6b4e80a5f976c..59973ef279a32 100644 --- a/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java +++ b/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java @@ -35,6 +35,19 @@ @JNINamespace("media") public class MediaPlayerBridge { + public static class ResourceLoadingFilter { + public boolean shouldOverrideResourceLoading( + MediaPlayer mediaPlayer, Context context, Uri uri) { + return false; + } + } + + private static ResourceLoadingFilter sResourceLoadFilter = null; + + public static void setResourceLoadingFilter(ResourceLoadingFilter filter) { + sResourceLoadFilter = filter; + } + private static final String TAG = "MediaPlayerBridge"; // Local player to forward this to. We don't initialize it here since the subclass might not @@ -152,6 +165,11 @@ protected boolean setDataSource( headersMap.put("allow-cross-domain-redirect", "false"); } try { + if (sResourceLoadFilter != null && + sResourceLoadFilter.shouldOverrideResourceLoading( + getLocalPlayer(), context, uri)) { + return true; + } getLocalPlayer().setDataSource(context, uri, headersMap); return true; } catch (Exception e) { diff --git a/media/base/android/media_player_bridge.cc b/media/base/android/media_player_bridge.cc index 37ea8c128a772..51628212ee9d4 100644 --- a/media/base/android/media_player_bridge.cc +++ b/media/base/android/media_player_bridge.cc @@ -64,7 +64,7 @@ MediaPlayerBridge::~MediaPlayerBridge() { void MediaPlayerBridge::Initialize() { cookies_.clear(); - if (url_.SchemeIsFile() || url_.SchemeIs("data")) { + if (url_.SchemeIsFile() || url_.SchemeIs("data") || url_.SchemeIs("app")) { ExtractMediaMetadata(url_.spec()); return; } diff --git a/media/cast/logging/logging_defines.h b/media/cast/logging/logging_defines.h index 021a3c99a7abc..0f57fe982d826 100644 --- a/media/cast/logging/logging_defines.h +++ b/media/cast/logging/logging_defines.h @@ -65,7 +65,10 @@ struct FrameEvent { EventMediaType media_type; - // Render / playout delay. Only set for FRAME_PLAYOUT events. + // Only set for FRAME_PLAYOUT events. + // If this value is zero the frame is rendered on time. + // If this value is positive it means the frame is rendered late. + // If this value is negative it means the frame is rendered early. base::TimeDelta delay_delta; // Whether the frame is a key frame. Only set for video FRAME_ENCODED event. diff --git a/media/cast/logging/stats_event_subscriber.cc b/media/cast/logging/stats_event_subscriber.cc index b22812e446e7f..c42affa401e7a 100644 --- a/media/cast/logging/stats_event_subscriber.cc +++ b/media/cast/logging/stats_event_subscriber.cc @@ -101,7 +101,12 @@ StatsEventSubscriber::StatsEventSubscriber( : event_media_type_(event_media_type), clock_(clock), offset_estimator_(offset_estimator), + capture_latency_datapoints_(0), + encode_time_datapoints_(0), + queueing_latency_datapoints_(0), network_latency_datapoints_(0), + packet_latency_datapoints_(0), + frame_latency_datapoints_(0), e2e_latency_datapoints_(0), num_frames_dropped_by_encoder_(0), num_frames_late_(0), @@ -150,7 +155,9 @@ void StatsEventSubscriber::OnReceiveFrameEvent(const FrameEvent& frame_event) { RecordE2ELatency(frame_event); base::TimeDelta delay_delta = frame_event.delay_delta; histograms_[PLAYOUT_DELAY_MS_HISTO]->Add(delay_delta.InMillisecondsF()); - if (delay_delta <= base::TimeDelta()) + + // Positive delay_delta means the frame is late. + if (delay_delta > base::TimeDelta()) num_frames_late_++; } @@ -182,7 +189,7 @@ void StatsEventSubscriber::OnReceivePacketEvent( if (type == PACKET_SENT_TO_NETWORK || type == PACKET_RECEIVED) { - RecordNetworkLatency(packet_event); + RecordPacketRelatedLatencies(packet_event); } else if (type == PACKET_RETRANSMITTED) { // We only measure network latency using packets that doesn't have to be // retransmitted as there is precisely one sent-receive timestamp pairs. @@ -226,6 +233,8 @@ scoped_ptr StatsEventSubscriber::GetStats() const { stats->SetDouble(CastStatToString(it->first), round(it->second * 1000.0) / 1000.0); } + + // Populate all histograms. for (HistogramMap::const_iterator it = histograms_.begin(); it != histograms_.end(); ++it) { @@ -244,8 +253,18 @@ void StatsEventSubscriber::Reset() { frame_stats_.clear(); packet_stats_.clear(); + total_capture_latency_ = base::TimeDelta(); + capture_latency_datapoints_ = 0; + total_encode_time_ = base::TimeDelta(); + encode_time_datapoints_ = 0; + total_queueing_latency_ = base::TimeDelta(); + queueing_latency_datapoints_ = 0; total_network_latency_ = base::TimeDelta(); network_latency_datapoints_ = 0; + total_packet_latency_ = base::TimeDelta(); + packet_latency_datapoints_ = 0; + total_frame_latency_ = base::TimeDelta(); + frame_latency_datapoints_ = 0; total_e2e_latency_ = base::TimeDelta(); e2e_latency_datapoints_ = 0; num_frames_dropped_by_encoder_ = 0; @@ -269,47 +288,75 @@ const char* StatsEventSubscriber::CastStatToString(CastStat stat) { STAT_ENUM_TO_STRING(CAPTURE_FPS); STAT_ENUM_TO_STRING(ENCODE_FPS); STAT_ENUM_TO_STRING(DECODE_FPS); + STAT_ENUM_TO_STRING(AVG_CAPTURE_LATENCY_MS); STAT_ENUM_TO_STRING(AVG_ENCODE_TIME_MS); - STAT_ENUM_TO_STRING(AVG_PLAYOUT_DELAY_MS); + STAT_ENUM_TO_STRING(AVG_QUEUEING_LATENCY_MS); STAT_ENUM_TO_STRING(AVG_NETWORK_LATENCY_MS); + STAT_ENUM_TO_STRING(AVG_PACKET_LATENCY_MS); + STAT_ENUM_TO_STRING(AVG_FRAME_LATENCY_MS); STAT_ENUM_TO_STRING(AVG_E2E_LATENCY_MS); STAT_ENUM_TO_STRING(ENCODE_KBPS); STAT_ENUM_TO_STRING(TRANSMISSION_KBPS); STAT_ENUM_TO_STRING(RETRANSMISSION_KBPS); - STAT_ENUM_TO_STRING(PACKET_LOSS_FRACTION); STAT_ENUM_TO_STRING(MS_SINCE_LAST_RECEIVER_RESPONSE); STAT_ENUM_TO_STRING(NUM_FRAMES_CAPTURED); STAT_ENUM_TO_STRING(NUM_FRAMES_DROPPED_BY_ENCODER); STAT_ENUM_TO_STRING(NUM_FRAMES_LATE); STAT_ENUM_TO_STRING(NUM_PACKETS_SENT); STAT_ENUM_TO_STRING(NUM_PACKETS_RETRANSMITTED); + STAT_ENUM_TO_STRING(NUM_PACKETS_RECEIVED); STAT_ENUM_TO_STRING(NUM_PACKETS_RTX_REJECTED); STAT_ENUM_TO_STRING(FIRST_EVENT_TIME_MS); STAT_ENUM_TO_STRING(LAST_EVENT_TIME_MS); STAT_ENUM_TO_STRING(CAPTURE_LATENCY_MS_HISTO); - STAT_ENUM_TO_STRING(ENCODE_LATENCY_MS_HISTO); + STAT_ENUM_TO_STRING(ENCODE_TIME_MS_HISTO); + STAT_ENUM_TO_STRING(QUEUEING_LATENCY_MS_HISTO); + STAT_ENUM_TO_STRING(NETWORK_LATENCY_MS_HISTO); STAT_ENUM_TO_STRING(PACKET_LATENCY_MS_HISTO); STAT_ENUM_TO_STRING(FRAME_LATENCY_MS_HISTO); + STAT_ENUM_TO_STRING(E2E_LATENCY_MS_HISTO); STAT_ENUM_TO_STRING(PLAYOUT_DELAY_MS_HISTO); } NOTREACHED(); return ""; } -const int kMaxLatencyBucketMs = 800; -const int kBucketWidthMs = 20; +const int kDefaultMaxLatencyBucketMs = 800; +const int kDefaultBucketWidthMs = 20; + +// For small latency values. +const int kSmallMaxLatencyBucketMs = 100; +const int kSmallBucketWidthMs = 5; + +// For large latency values. +const int kLargeMaxLatencyBucketMs = 1200; +const int kLargeBucketWidthMs = 50; void StatsEventSubscriber::InitHistograms() { - histograms_[CAPTURE_LATENCY_MS_HISTO].reset( - new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs)); - histograms_[ENCODE_LATENCY_MS_HISTO].reset( - new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs)); + histograms_[E2E_LATENCY_MS_HISTO].reset( + new SimpleHistogram(0, kLargeMaxLatencyBucketMs, + kLargeBucketWidthMs)); + histograms_[QUEUEING_LATENCY_MS_HISTO].reset( + new SimpleHistogram(0, kDefaultMaxLatencyBucketMs, + kDefaultBucketWidthMs)); + histograms_[NETWORK_LATENCY_MS_HISTO].reset( + new SimpleHistogram(0, kDefaultMaxLatencyBucketMs, + kDefaultBucketWidthMs)); histograms_[PACKET_LATENCY_MS_HISTO].reset( - new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs)); + new SimpleHistogram(0, kDefaultMaxLatencyBucketMs, + kDefaultBucketWidthMs)); histograms_[FRAME_LATENCY_MS_HISTO].reset( - new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs)); + new SimpleHistogram(0, kDefaultMaxLatencyBucketMs, + kDefaultBucketWidthMs)); histograms_[PLAYOUT_DELAY_MS_HISTO].reset( - new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs)); + new SimpleHistogram(0, kSmallMaxLatencyBucketMs, + kSmallBucketWidthMs)); + histograms_[CAPTURE_LATENCY_MS_HISTO].reset( + new SimpleHistogram(0, kSmallMaxLatencyBucketMs, + kSmallBucketWidthMs)); + histograms_[ENCODE_TIME_MS_HISTO].reset( + new SimpleHistogram(0, kSmallMaxLatencyBucketMs, + kSmallBucketWidthMs)); } void StatsEventSubscriber::GetStatsInternal(StatsMap* stats_map) const { @@ -325,7 +372,6 @@ void StatsEventSubscriber::GetStatsInternal(StatsMap* stats_map) const { end_time, FRAME_ENCODED, ENCODE_FPS, stats_map); PopulateFpsStat( end_time, FRAME_DECODED, DECODE_FPS, stats_map); - PopulatePlayoutDelayStat(stats_map); PopulateFrameBitrateStat(end_time, stats_map); PopulatePacketBitrateStat(end_time, PACKET_SENT_TO_NETWORK, @@ -335,14 +381,38 @@ void StatsEventSubscriber::GetStatsInternal(StatsMap* stats_map) const { PACKET_RETRANSMITTED, RETRANSMISSION_KBPS, stats_map); - PopulatePacketLossPercentageStat(stats_map); PopulateFrameCountStat(FRAME_CAPTURE_END, NUM_FRAMES_CAPTURED, stats_map); PopulatePacketCountStat(PACKET_SENT_TO_NETWORK, NUM_PACKETS_SENT, stats_map); PopulatePacketCountStat( PACKET_RETRANSMITTED, NUM_PACKETS_RETRANSMITTED, stats_map); + PopulatePacketCountStat(PACKET_RECEIVED, NUM_PACKETS_RECEIVED, stats_map); PopulatePacketCountStat( PACKET_RTX_REJECTED, NUM_PACKETS_RTX_REJECTED, stats_map); + if (capture_latency_datapoints_ > 0) { + double avg_capture_latency_ms = + total_capture_latency_.InMillisecondsF() / + capture_latency_datapoints_; + stats_map->insert( + std::make_pair(AVG_CAPTURE_LATENCY_MS, avg_capture_latency_ms)); + } + + if (encode_time_datapoints_ > 0) { + double avg_encode_time_ms = + total_encode_time_.InMillisecondsF() / + encode_time_datapoints_; + stats_map->insert( + std::make_pair(AVG_ENCODE_TIME_MS, avg_encode_time_ms)); + } + + if (queueing_latency_datapoints_ > 0) { + double avg_queueing_latency_ms = + total_queueing_latency_.InMillisecondsF() / + queueing_latency_datapoints_; + stats_map->insert( + std::make_pair(AVG_QUEUEING_LATENCY_MS, avg_queueing_latency_ms)); + } + if (network_latency_datapoints_ > 0) { double avg_network_latency_ms = total_network_latency_.InMillisecondsF() / @@ -351,6 +421,21 @@ void StatsEventSubscriber::GetStatsInternal(StatsMap* stats_map) const { std::make_pair(AVG_NETWORK_LATENCY_MS, avg_network_latency_ms)); } + if (packet_latency_datapoints_ > 0) { + double avg_packet_latency_ms = + total_packet_latency_.InMillisecondsF() / + packet_latency_datapoints_; + stats_map->insert( + std::make_pair(AVG_PACKET_LATENCY_MS, avg_packet_latency_ms)); + } + + if (frame_latency_datapoints_ > 0) { + double avg_frame_latency_ms = + total_frame_latency_.InMillisecondsF() / frame_latency_datapoints_; + stats_map->insert( + std::make_pair(AVG_FRAME_LATENCY_MS, avg_frame_latency_ms)); + } + if (e2e_latency_datapoints_ > 0) { double avg_e2e_latency_ms = total_e2e_latency_.InMillisecondsF() / e2e_latency_datapoints_; @@ -378,6 +463,13 @@ void StatsEventSubscriber::GetStatsInternal(StatsMap* stats_map) const { } } +StatsEventSubscriber::SimpleHistogram* +StatsEventSubscriber::GetHistogramForTesting( + CastStat stats) const { + DCHECK(histograms_.find(stats) != histograms_.end()); + return histograms_.find(stats)->second.get(); +} + bool StatsEventSubscriber::GetReceiverOffset(base::TimeDelta* offset) { base::TimeDelta receiver_offset_lower_bound; base::TimeDelta receiver_offset_upper_bound; @@ -403,7 +495,7 @@ void StatsEventSubscriber::MaybeInsertFrameInfo(RtpTimestamp rtp_timestamp, if (recent_frame_infos_.size() >= kMaxFrameInfoMapSize) { FrameInfoMap::iterator erase_it = recent_frame_infos_.begin(); - if (erase_it->second.encode_time.is_null()) + if (erase_it->second.encode_end_time.is_null()) num_frames_dropped_by_encoder_++; recent_frame_infos_.erase(erase_it); } @@ -419,13 +511,15 @@ void StatsEventSubscriber::RecordFrameCaptureTime( void StatsEventSubscriber::RecordCaptureLatency(const FrameEvent& frame_event) { FrameInfoMap::iterator it = recent_frame_infos_.find(frame_event.rtp_timestamp); - if (it == recent_frame_infos_.end()) + if (it == recent_frame_infos_.end()) { return; + } if (!it->second.capture_time.is_null()) { - double capture_latency_ms = - (it->second.capture_time - frame_event.timestamp).InMillisecondsF(); - histograms_[CAPTURE_LATENCY_MS_HISTO]->Add(capture_latency_ms); + base::TimeDelta latency = frame_event.timestamp - it->second.capture_time; + total_capture_latency_ += latency; + capture_latency_datapoints_++; + histograms_[CAPTURE_LATENCY_MS_HISTO]->Add(latency.InMillisecondsF()); } it->second.capture_end_time = frame_event.timestamp; @@ -436,18 +530,20 @@ void StatsEventSubscriber::RecordEncodeLatency(const FrameEvent& frame_event) { recent_frame_infos_.find(frame_event.rtp_timestamp); if (it == recent_frame_infos_.end()) { FrameInfo frame_info; - frame_info.encode_time = frame_event.timestamp; + frame_info.encode_end_time = frame_event.timestamp; MaybeInsertFrameInfo(frame_event.rtp_timestamp, frame_info); return; } if (!it->second.capture_end_time.is_null()) { - double encode_latency_ms = - (frame_event.timestamp - it->second.capture_end_time).InMillisecondsF(); - histograms_[ENCODE_LATENCY_MS_HISTO]->Add(encode_latency_ms); + base::TimeDelta latency = + frame_event.timestamp - it->second.capture_end_time; + total_encode_time_ += latency; + encode_time_datapoints_++; + histograms_[ENCODE_TIME_MS_HISTO]->Add(latency.InMillisecondsF()); } - it->second.encode_time = frame_event.timestamp; + it->second.encode_end_time = frame_event.timestamp; } void StatsEventSubscriber::RecordFrameTxLatency(const FrameEvent& frame_event) { @@ -456,7 +552,7 @@ void StatsEventSubscriber::RecordFrameTxLatency(const FrameEvent& frame_event) { if (it == recent_frame_infos_.end()) return; - if (it->second.encode_time.is_null()) + if (it->second.encode_end_time.is_null()) return; base::TimeDelta receiver_offset; @@ -464,9 +560,10 @@ void StatsEventSubscriber::RecordFrameTxLatency(const FrameEvent& frame_event) { return; base::TimeTicks sender_time = frame_event.timestamp - receiver_offset; - double frame_tx_latency_ms = - (sender_time - it->second.encode_time).InMillisecondsF(); - histograms_[FRAME_LATENCY_MS_HISTO]->Add(frame_tx_latency_ms); + base::TimeDelta latency = sender_time - it->second.encode_end_time; + total_frame_latency_ += latency; + frame_latency_datapoints_++; + histograms_[FRAME_LATENCY_MS_HISTO]->Add(latency.InMillisecondsF()); } void StatsEventSubscriber::RecordE2ELatency(const FrameEvent& frame_event) { @@ -482,8 +579,10 @@ void StatsEventSubscriber::RecordE2ELatency(const FrameEvent& frame_event) { // Playout time is event time + playout delay. base::TimeTicks playout_time = frame_event.timestamp + frame_event.delay_delta - receiver_offset; - total_e2e_latency_ += playout_time - it->second.capture_time; + base::TimeDelta latency = playout_time - it->second.capture_time; + total_e2e_latency_ += latency; e2e_latency_datapoints_++; + histograms_[E2E_LATENCY_MS_HISTO]->Add(latency.InMillisecondsF()); } void StatsEventSubscriber::UpdateLastResponseTime( @@ -502,8 +601,23 @@ void StatsEventSubscriber::ErasePacketSentTime( packet_sent_times_.erase(key); } -void StatsEventSubscriber::RecordNetworkLatency( +void StatsEventSubscriber::RecordPacketRelatedLatencies( const PacketEvent& packet_event) { + // Log queueing latency. + if (packet_event.type == PACKET_SENT_TO_NETWORK) { + FrameInfoMap::iterator it = + recent_frame_infos_.find(packet_event.rtp_timestamp); + if (it != recent_frame_infos_.end()) { + base::TimeDelta latency = + packet_event.timestamp - it->second.encode_end_time; + total_queueing_latency_ += latency; + queueing_latency_datapoints_++; + histograms_[QUEUEING_LATENCY_MS_HISTO]->Add( + latency.InMillisecondsF()); + } + } + + // Log network latency and total packet latency; base::TimeDelta receiver_offset; if (!GetReceiverOffset(&receiver_offset)) return; @@ -535,17 +649,28 @@ void StatsEventSubscriber::RecordNetworkLatency( match = true; } if (match) { + packet_sent_times_.erase(it); + // Subtract by offset. packet_received_time -= receiver_offset; base::TimeDelta latency_delta = packet_received_time - packet_sent_time; total_network_latency_ += latency_delta; network_latency_datapoints_++; - - histograms_[PACKET_LATENCY_MS_HISTO]->Add( + histograms_[NETWORK_LATENCY_MS_HISTO]->Add( latency_delta.InMillisecondsF()); - packet_sent_times_.erase(it); + // Log total network latency. + FrameInfoMap::iterator frame_it = + recent_frame_infos_.find(packet_event.rtp_timestamp); + if (frame_it != recent_frame_infos_.end()) { + base::TimeDelta latency = + packet_received_time - frame_it->second.encode_end_time; + total_packet_latency_ += latency; + packet_latency_datapoints_++; + histograms_[PACKET_LATENCY_MS_HISTO]->Add( + latency.InMillisecondsF()); + } } } } @@ -583,18 +708,6 @@ void StatsEventSubscriber::PopulatePacketCountStat(CastLoggingEvent event, } } -void StatsEventSubscriber::PopulatePlayoutDelayStat(StatsMap* stats_map) const { - FrameStatsMap::const_iterator it = frame_stats_.find(FRAME_PLAYOUT); - if (it != frame_stats_.end()) { - double avg_delay_ms = 0.0; - base::TimeDelta sum_delay = it->second.sum_delay; - int count = it->second.event_counter; - if (count != 0) - avg_delay_ms = sum_delay.InMillisecondsF() / count; - stats_map->insert(std::make_pair(AVG_PLAYOUT_DELAY_MS, avg_delay_ms)); - } -} - void StatsEventSubscriber::PopulateFrameBitrateStat(base::TimeTicks end_time, StatsMap* stats_map) const { FrameStatsMap::const_iterator it = frame_stats_.find(FRAME_ENCODED); @@ -626,28 +739,6 @@ void StatsEventSubscriber::PopulatePacketBitrateStat( } } -void StatsEventSubscriber::PopulatePacketLossPercentageStat( - StatsMap* stats_map) const { - // We assume that retransmission means that the packet's previous - // (re)transmission was lost. - // This means the percentage of packet loss is - // (# of retransmit events) / (# of transmit + retransmit events). - PacketStatsMap::const_iterator sent_it = - packet_stats_.find(PACKET_SENT_TO_NETWORK); - if (sent_it == packet_stats_.end()) - return; - PacketStatsMap::const_iterator retransmitted_it = - packet_stats_.find(PACKET_RETRANSMITTED); - int sent_count = sent_it->second.event_counter; - int retransmitted_count = 0; - if (retransmitted_it != packet_stats_.end()) - retransmitted_count = retransmitted_it->second.event_counter; - double packet_loss_fraction = static_cast(retransmitted_count) / - (sent_count + retransmitted_count); - stats_map->insert( - std::make_pair(PACKET_LOSS_FRACTION, packet_loss_fraction)); -} - StatsEventSubscriber::FrameLogStats::FrameLogStats() : event_counter(0), sum_size(0) {} StatsEventSubscriber::FrameLogStats::~FrameLogStats() {} diff --git a/media/cast/logging/stats_event_subscriber.h b/media/cast/logging/stats_event_subscriber.h index 20394021bdc2f..3e8c83b153a97 100644 --- a/media/cast/logging/stats_event_subscriber.h +++ b/media/cast/logging/stats_event_subscriber.h @@ -57,6 +57,7 @@ class StatsEventSubscriber : public RawEventSubscriber { FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, PlayoutDelay); FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, E2ELatency); FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, Packets); + FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, Histograms); static const size_t kMaxFrameInfoMapSize = 100; @@ -113,15 +114,22 @@ class StatsEventSubscriber : public RawEventSubscriber { ENCODE_FPS, // Decode frame rate. DECODE_FPS, + // Average capture latency in milliseconds. + AVG_CAPTURE_LATENCY_MS, // Average encode duration in milliseconds. - // TODO(imcheng): This stat is not populated yet because we do not have - // the time when encode started. Record it in FRAME_ENCODED event. AVG_ENCODE_TIME_MS, - // Average playout delay in milliseconds. - AVG_PLAYOUT_DELAY_MS, + // Duration from when a frame is encoded to when the packet is first + // sent. + AVG_QUEUEING_LATENCY_MS, // Duration from when a packet is transmitted to when it is received. // This measures latency from sender to receiver. AVG_NETWORK_LATENCY_MS, + // Duration from when a frame is encoded to when the packet is first + // received. + AVG_PACKET_LATENCY_MS, + // Average latency between frame encoded and the moment when the frame + // is fully received. + AVG_FRAME_LATENCY_MS, // Duration from when a frame is captured to when it should be played out. AVG_E2E_LATENCY_MS, // Encode bitrate in kbps. @@ -130,8 +138,6 @@ class StatsEventSubscriber : public RawEventSubscriber { TRANSMISSION_KBPS, // Packet retransmission bitrate in kbps. RETRANSMISSION_KBPS, - // Fraction of packet loss. - PACKET_LOSS_FRACTION, // Duration in milliseconds since last receiver response. MS_SINCE_LAST_RECEIVER_RESPONSE, // Number of frames captured. @@ -144,6 +150,8 @@ class StatsEventSubscriber : public RawEventSubscriber { NUM_PACKETS_SENT, // Number of packets that were retransmitted. NUM_PACKETS_RETRANSMITTED, + // Number of packets that were received by receiver. + NUM_PACKETS_RECEIVED, // Number of packets that had their retransmission cancelled. NUM_PACKETS_RTX_REJECTED, // Unix time in milliseconds of first event since reset. @@ -153,9 +161,12 @@ class StatsEventSubscriber : public RawEventSubscriber { // Histograms CAPTURE_LATENCY_MS_HISTO, - ENCODE_LATENCY_MS_HISTO, + ENCODE_TIME_MS_HISTO, + QUEUEING_LATENCY_MS_HISTO, + NETWORK_LATENCY_MS_HISTO, PACKET_LATENCY_MS_HISTO, FRAME_LATENCY_MS_HISTO, + E2E_LATENCY_MS_HISTO, PLAYOUT_DELAY_MS_HISTO }; @@ -165,7 +176,7 @@ class StatsEventSubscriber : public RawEventSubscriber { base::TimeTicks capture_time; base::TimeTicks capture_end_time; - base::TimeTicks encode_time; + base::TimeTicks encode_end_time; bool encoded; }; @@ -186,6 +197,9 @@ class StatsEventSubscriber : public RawEventSubscriber { // Assigns |stats_map| with stats data. Used for testing. void GetStatsInternal(StatsMap* stats_map) const; + // Return a histogram of the type specified. + SimpleHistogram* GetHistogramForTesting(CastStat stats) const; + void UpdateFirstLastEventTime(base::TimeTicks timestamp, bool is_receiver_event); bool GetReceiverOffset(base::TimeDelta* offset); @@ -198,7 +212,7 @@ class StatsEventSubscriber : public RawEventSubscriber { void RecordE2ELatency(const FrameEvent& frame_event); void RecordPacketSentTime(const PacketEvent& packet_event); void ErasePacketSentTime(const PacketEvent& packet_event); - void RecordNetworkLatency(const PacketEvent& packet_event); + void RecordPacketRelatedLatencies(const PacketEvent& packet_event); void UpdateLastResponseTime(base::TimeTicks receiver_time); void PopulateFpsStat(base::TimeTicks now, @@ -211,13 +225,11 @@ class StatsEventSubscriber : public RawEventSubscriber { void PopulatePacketCountStat(CastLoggingEvent event, CastStat stat, StatsMap* stats_map) const; - void PopulatePlayoutDelayStat(StatsMap* stats_map) const; void PopulateFrameBitrateStat(base::TimeTicks now, StatsMap* stats_map) const; void PopulatePacketBitrateStat(base::TimeTicks now, CastLoggingEvent event, CastStat stat, StatsMap* stats_map) const; - void PopulatePacketLossPercentageStat(StatsMap* stats_map) const; const EventMediaType event_media_type_; @@ -230,8 +242,18 @@ class StatsEventSubscriber : public RawEventSubscriber { FrameStatsMap frame_stats_; PacketStatsMap packet_stats_; + base::TimeDelta total_capture_latency_; + int capture_latency_datapoints_; + base::TimeDelta total_encode_time_; + int encode_time_datapoints_; + base::TimeDelta total_queueing_latency_; + int queueing_latency_datapoints_; base::TimeDelta total_network_latency_; int network_latency_datapoints_; + base::TimeDelta total_packet_latency_; + int packet_latency_datapoints_; + base::TimeDelta total_frame_latency_; + int frame_latency_datapoints_; base::TimeDelta total_e2e_latency_; int e2e_latency_datapoints_; diff --git a/media/cast/logging/stats_event_subscriber_unittest.cc b/media/cast/logging/stats_event_subscriber_unittest.cc index 41388e0ade05f..570e2ccf3a58d 100644 --- a/media/cast/logging/stats_event_subscriber_unittest.cc +++ b/media/cast/logging/stats_event_subscriber_unittest.cc @@ -131,6 +131,11 @@ TEST_F(StatsEventSubscriberTest, CaptureEncode) { ASSERT_TRUE(it != stats_map.end()); EXPECT_DOUBLE_EQ(it->second, static_cast(dropped_frames)); + + it = stats_map.find(StatsEventSubscriber::AVG_CAPTURE_LATENCY_MS); + ASSERT_TRUE(it != stats_map.end()); + + EXPECT_DOUBLE_EQ(it->second, static_cast(0.01)); } TEST_F(StatsEventSubscriberTest, Encode) { @@ -236,12 +241,10 @@ TEST_F(StatsEventSubscriberTest, PlayoutDelay) { uint32 rtp_timestamp = 0; uint32 frame_id = 0; int num_frames = 10; - int total_delay_ms = 0; int late_frames = 0; for (int i = 0, delay_ms = -50; i < num_frames; i++, delay_ms += 10) { base::TimeDelta delay = base::TimeDelta::FromMilliseconds(delay_ms); - total_delay_ms += delay_ms; - if (delay_ms <= 0) + if (delay_ms > 0) late_frames++; cast_environment_->Logging()->InsertFrameEventWithDelay( receiver_clock_.NowTicks(), @@ -259,14 +262,8 @@ TEST_F(StatsEventSubscriberTest, PlayoutDelay) { StatsEventSubscriber::StatsMap stats_map; subscriber_->GetStatsInternal(&stats_map); - StatsEventSubscriber::StatsMap::iterator it = - stats_map.find(StatsEventSubscriber::AVG_PLAYOUT_DELAY_MS); - ASSERT_TRUE(it != stats_map.end()); - - EXPECT_DOUBLE_EQ( - it->second, static_cast(total_delay_ms) / num_frames); - - it = stats_map.find(StatsEventSubscriber::NUM_FRAMES_LATE); + StatsEventSubscriber::StatsMap::iterator it = stats_map.find( + StatsEventSubscriber::NUM_FRAMES_LATE); ASSERT_TRUE(it != stats_map.end()); EXPECT_DOUBLE_EQ(it->second, late_frames); @@ -326,10 +323,22 @@ TEST_F(StatsEventSubscriberTest, Packets) { base::TimeTicks start_time = sender_clock_->NowTicks(); int total_size = 0; int retransmit_total_size = 0; - base::TimeDelta total_latency; + base::TimeDelta total_network_latency; + base::TimeDelta total_queueing_latency; + base::TimeDelta total_packet_latency; int num_packets_transmitted = 0; + int num_packets_received = 0; int num_packets_retransmitted = 0; int num_packets_rtx_rejected = 0; + + base::TimeTicks sender_encoded_time = sender_clock_->NowTicks(); + base::TimeTicks receiver_encoded_time = receiver_clock_.NowTicks(); + cast_environment_->Logging()->InsertFrameEvent(sender_encoded_time, + FRAME_ENCODED, + VIDEO_EVENT, + rtp_timestamp, + 0); + // Every 2nd packet will be retransmitted once. // Every 4th packet will be retransmitted twice. // Every 8th packet will be retransmitted 3 times + 1 rejected retransmission. @@ -346,12 +355,15 @@ TEST_F(StatsEventSubscriberTest, Packets) { num_packets - 1, size); num_packets_transmitted++; + total_queueing_latency += sender_clock_->NowTicks() - sender_encoded_time; int latency_micros = 20000 + base::RandInt(-10000, 10000); base::TimeDelta latency = base::TimeDelta::FromMicroseconds(latency_micros); // Latency is only recorded for packets that aren't retransmitted. if (i % 2 != 0) { - total_latency += latency; + total_network_latency += latency; + total_packet_latency += + receiver_clock_.NowTicks() - receiver_encoded_time + latency; num_latency_recorded_packets++; } @@ -428,6 +440,7 @@ TEST_F(StatsEventSubscriberTest, Packets) { i, num_packets - 1, size); + num_packets_received++; } base::TimeTicks end_time = sender_clock_->NowTicks(); @@ -436,15 +449,28 @@ TEST_F(StatsEventSubscriberTest, Packets) { StatsEventSubscriber::StatsMap stats_map; subscriber_->GetStatsInternal(&stats_map); - // Measure AVG_NETWORK_LATENCY_MS, TRANSMISSION_KBPS, RETRANSMISSION_KBPS, - // and PACKET_LOSS_FRACTION. + // Measure AVG_NETWORK_LATENCY_MS, TRANSMISSION_KBPS, RETRANSMISSION_KBPS. StatsEventSubscriber::StatsMap::iterator it = stats_map.find(StatsEventSubscriber::AVG_NETWORK_LATENCY_MS); ASSERT_TRUE(it != stats_map.end()); EXPECT_DOUBLE_EQ( it->second, - total_latency.InMillisecondsF() / num_latency_recorded_packets); + total_network_latency.InMillisecondsF() / num_latency_recorded_packets); + + it = stats_map.find(StatsEventSubscriber::AVG_QUEUEING_LATENCY_MS); + ASSERT_TRUE(it != stats_map.end()); + + EXPECT_DOUBLE_EQ( + it->second, + total_queueing_latency.InMillisecondsF() / num_packets); + + it = stats_map.find(StatsEventSubscriber::AVG_PACKET_LATENCY_MS); + ASSERT_TRUE(it != stats_map.end()); + + EXPECT_DOUBLE_EQ( + it->second, + total_packet_latency.InMillisecondsF() / num_latency_recorded_packets); it = stats_map.find(StatsEventSubscriber::TRANSMISSION_KBPS); ASSERT_TRUE(it != stats_map.end()); @@ -459,17 +485,15 @@ TEST_F(StatsEventSubscriberTest, Packets) { static_cast(retransmit_total_size) / duration.InMillisecondsF() * 8); - it = stats_map.find(StatsEventSubscriber::PACKET_LOSS_FRACTION); + it = stats_map.find(StatsEventSubscriber::NUM_PACKETS_SENT); ASSERT_TRUE(it != stats_map.end()); - EXPECT_DOUBLE_EQ( - it->second, - static_cast(num_packets_retransmitted) / num_packets_transmitted); + EXPECT_DOUBLE_EQ(it->second, static_cast(num_packets)); - it = stats_map.find(StatsEventSubscriber::NUM_PACKETS_SENT); + it = stats_map.find(StatsEventSubscriber::NUM_PACKETS_RECEIVED); ASSERT_TRUE(it != stats_map.end()); - EXPECT_DOUBLE_EQ(it->second, static_cast(num_packets)); + EXPECT_DOUBLE_EQ(it->second, static_cast(num_packets_received)); it = stats_map.find(StatsEventSubscriber::NUM_PACKETS_RETRANSMITTED); ASSERT_TRUE(it != stats_map.end()); @@ -482,5 +506,122 @@ TEST_F(StatsEventSubscriberTest, Packets) { EXPECT_DOUBLE_EQ(it->second, static_cast(num_packets_rtx_rejected)); } +bool CheckHistogramHasValue(base::ListValue* values, + const std::string& bucket, int expected_count) { + for (size_t i = 0; i < values->GetSize(); ++i) { + const base::DictionaryValue* dict = NULL; + values->GetDictionary(i, &dict); + if (!dict->HasKey(bucket)) + continue; + int bucket_count = 0; + if (!dict->GetInteger(bucket, &bucket_count)) + return false; + return bucket_count == expected_count; + } + return false; +} + +TEST_F(StatsEventSubscriberTest, Histograms) { + Init(VIDEO_EVENT); + AdvanceClocks(base::TimeDelta::FromMilliseconds(123)); + + uint32 rtp_timestamp = 123; + uint32 frame_id = 0; + + // 10 Frames with capture latency in the bucket of "10-14"ms. + // 10 Frames with encode time in the bucket of "15-19"ms. + for (int i = 0; i < 10; ++i) { + ++frame_id; + ++rtp_timestamp; + cast_environment_->Logging()->InsertFrameEvent(sender_clock_->NowTicks(), + FRAME_CAPTURE_BEGIN, + VIDEO_EVENT, + rtp_timestamp, + frame_id); + AdvanceClocks(base::TimeDelta::FromMilliseconds(10)); + cast_environment_->Logging()->InsertFrameEvent(sender_clock_->NowTicks(), + FRAME_CAPTURE_END, + VIDEO_EVENT, + rtp_timestamp, + frame_id); + AdvanceClocks(base::TimeDelta::FromMilliseconds(15)); + cast_environment_->Logging()->InsertEncodedFrameEvent( + sender_clock_->NowTicks(), + FRAME_ENCODED, + VIDEO_EVENT, + rtp_timestamp, + frame_id, + 1024, + true, + 5678); + } + + // Send 3 packets for the last frame. + // Queueing latencies are 100ms, 200ms and 300ms. + for (int i = 0; i < 3; ++i) { + AdvanceClocks(base::TimeDelta::FromMilliseconds(100)); + cast_environment_->Logging()->InsertPacketEvent(sender_clock_->NowTicks(), + PACKET_SENT_TO_NETWORK, + VIDEO_EVENT, + rtp_timestamp, + 0, + i, + 2, + 123); + } + + // Receive 3 packets for the last frame. + // Network latencies are 100ms, 200ms and 300ms. + // Packet latencies are 400ms. + AdvanceClocks(base::TimeDelta::FromMilliseconds(100)); + for (int i = 0; i < 3; ++i) { + cast_environment_->Logging()->InsertPacketEvent(receiver_clock_.NowTicks(), + PACKET_RECEIVED, + VIDEO_EVENT, + rtp_timestamp, + 0, + i, + 2, + 123); + } + + StatsEventSubscriber::SimpleHistogram* histogram; + scoped_ptr values; + + histogram = subscriber_->GetHistogramForTesting( + StatsEventSubscriber::CAPTURE_LATENCY_MS_HISTO); + ASSERT_TRUE(histogram); + values = histogram->GetHistogram().Pass(); + EXPECT_TRUE(CheckHistogramHasValue(values.get(), "10-14", 10)); + + histogram = subscriber_->GetHistogramForTesting( + StatsEventSubscriber::ENCODE_TIME_MS_HISTO); + ASSERT_TRUE(histogram); + values = histogram->GetHistogram().Pass(); + EXPECT_TRUE(CheckHistogramHasValue(values.get(), "15-19", 10)); + + histogram = subscriber_->GetHistogramForTesting( + StatsEventSubscriber::QUEUEING_LATENCY_MS_HISTO); + ASSERT_TRUE(histogram); + values = histogram->GetHistogram().Pass(); + EXPECT_TRUE(CheckHistogramHasValue(values.get(), "100-119", 1)); + EXPECT_TRUE(CheckHistogramHasValue(values.get(), "200-219", 1)); + EXPECT_TRUE(CheckHistogramHasValue(values.get(), "300-319", 1)); + + histogram = subscriber_->GetHistogramForTesting( + StatsEventSubscriber::NETWORK_LATENCY_MS_HISTO); + ASSERT_TRUE(histogram); + values = histogram->GetHistogram().Pass(); + EXPECT_TRUE(CheckHistogramHasValue(values.get(), "100-119", 1)); + EXPECT_TRUE(CheckHistogramHasValue(values.get(), "200-219", 1)); + EXPECT_TRUE(CheckHistogramHasValue(values.get(), "300-319", 1)); + + histogram = subscriber_->GetHistogramForTesting( + StatsEventSubscriber::PACKET_LATENCY_MS_HISTO); + ASSERT_TRUE(histogram); + values = histogram->GetHistogram().Pass(); + EXPECT_TRUE(CheckHistogramHasValue(values.get(), "400-419", 3)); +} + } // namespace cast } // namespace media diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc index 3b92d3db70672..c468d9574c644 100644 --- a/media/ffmpeg/ffmpeg_common.cc +++ b/media/ffmpeg/ffmpeg_common.cc @@ -61,7 +61,7 @@ int64 ConvertToTimeBase(const AVRational& time_base, } // Converts an FFmpeg audio codec ID into its corresponding supported codec id. -static AudioCodec CodecIDToAudioCodec(AVCodecID codec_id) { +AudioCodec CodecIDToAudioCodec(AVCodecID codec_id) { switch (codec_id) { case AV_CODEC_ID_AAC: return kCodecAAC; @@ -146,7 +146,7 @@ static AVCodecID AudioCodecToCodecID(AudioCodec audio_codec, } // Converts an FFmpeg video codec ID into its corresponding supported codec id. -static VideoCodec CodecIDToVideoCodec(AVCodecID codec_id) { +VideoCodec CodecIDToVideoCodec(AVCodecID codec_id) { switch (codec_id) { case AV_CODEC_ID_H264: return kCodecH264; diff --git a/media/ffmpeg/ffmpeg_common.h b/media/ffmpeg/ffmpeg_common.h index 3616a150aab39..fba61498508e2 100644 --- a/media/ffmpeg/ffmpeg_common.h +++ b/media/ffmpeg/ffmpeg_common.h @@ -128,6 +128,10 @@ PixelFormat VideoFormatToPixelFormat(VideoFrame::Format video_format); // date string. Otherwise returns fals and timeline_offset is unmodified. MEDIA_EXPORT bool FFmpegUTCDateToTime(const char* date_utc, base::Time* out); +MEDIA_EXPORT AudioCodec CodecIDToAudioCodec(AVCodecID codec_id); + +MEDIA_EXPORT VideoCodec CodecIDToVideoCodec(AVCodecID codec_id); + } // namespace media #endif // MEDIA_FFMPEG_FFMPEG_COMMON_H_ diff --git a/native_client_sdk/src/build_tools/build_sdk.py b/native_client_sdk/src/build_tools/build_sdk.py index cac1e0c61c693..1d9c6ed0f16d4 100755 --- a/native_client_sdk/src/build_tools/build_sdk.py +++ b/native_client_sdk/src/build_tools/build_sdk.py @@ -57,7 +57,7 @@ PKGVER = os.path.join(BUILD_DIR, 'package_version', 'package_version.py') NACLPORTS_URL = 'https://chromium.googlesource.com/external/naclports.git' -NACLPORTS_REV = '873ca4910a5f9d4206306aacb4ed79c587c6a5f3' +NACLPORTS_REV = 'e53078c33d99b0b3cbadbbbbb92cccf7a48d5dc1' GYPBUILD_DIR = 'gypbuild' diff --git a/native_client_sdk/src/gonacl_appengine/src/bullet/build.sh b/native_client_sdk/src/gonacl_appengine/src/bullet/build.sh index 0c499586f7da0..55a0fd9e119b6 100755 --- a/native_client_sdk/src/gonacl_appengine/src/bullet/build.sh +++ b/native_client_sdk/src/gonacl_appengine/src/bullet/build.sh @@ -11,7 +11,7 @@ cd ${SCRIPT_DIR} OUT_DIR=out NACLPORTS_URL=https://chromium.googlesource.com/external/naclports.git -NACLPORTS_SHA=873ca4910a5f9d4206306aacb4ed79c587c6a5f3 +NACLPORTS_SHA=e53078c33d99b0b3cbadbbbbb92cccf7a48d5dc1 NACLPORTS_DIR=${OUT_DIR}/naclports NACLAM_URL=https://github.com/johnmccutchan/NaClAMBase NACLAM_DIR=${OUT_DIR}/NaClAMBase diff --git a/native_client_sdk/src/gonacl_appengine/src/lua/build.sh b/native_client_sdk/src/gonacl_appengine/src/lua/build.sh index ac1475907c1fe..c1afeb0ec3dfe 100755 --- a/native_client_sdk/src/gonacl_appengine/src/lua/build.sh +++ b/native_client_sdk/src/gonacl_appengine/src/lua/build.sh @@ -11,7 +11,7 @@ cd ${SCRIPT_DIR} OUT_DIR=out NACLPORTS_URL=https://chromium.googlesource.com/external/naclports.git -NACLPORTS_REV=873ca4910a5f9d4206306aacb4ed79c587c6a5f3 +NACLPORTS_REV=e53078c33d99b0b3cbadbbbbb92cccf7a48d5dc1 NACLPORTS_DIR=${OUT_DIR}/naclports if [ -z "${NACL_SDK_ROOT:-}" ]; then diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h index 4b61e0e311ae2..89fbfff08c1cc 100644 --- a/net/base/net_error_list.h +++ b/net/base/net_error_list.h @@ -444,16 +444,13 @@ NET_ERROR(CERT_WEAK_KEY, -211) // The certificate claimed DNS names that are in violation of name constraints. NET_ERROR(CERT_NAME_CONSTRAINT_VIOLATION, -212) -// The certificate's validity period is too long. -NET_ERROR(CERT_VALIDITY_TOO_LONG, -213) - // Add new certificate error codes here. // // Update the value of CERT_END whenever you add a new certificate error // code. // The value immediately past the last certificate error code. -NET_ERROR(CERT_END, -214) +NET_ERROR(CERT_END, -213) // The URL is invalid. NET_ERROR(INVALID_URL, -300) diff --git a/net/cert/cert_status_flags.cc b/net/cert/cert_status_flags.cc index e8d9aab0c1dac..d278ea47b453b 100644 --- a/net/cert/cert_status_flags.cc +++ b/net/cert/cert_status_flags.cc @@ -49,8 +49,6 @@ CertStatus MapNetErrorToCertStatus(int error) { return CERT_STATUS_PINNED_KEY_MISSING; case ERR_CERT_NAME_CONSTRAINT_VIOLATION: return CERT_STATUS_NAME_CONSTRAINT_VIOLATION; - case ERR_CERT_VALIDITY_TOO_LONG: - return CERT_STATUS_VALIDITY_TOO_LONG; default: return 0; } @@ -83,8 +81,6 @@ int MapCertStatusToNetError(CertStatus cert_status) { return ERR_CERT_WEAK_KEY; if (cert_status & CERT_STATUS_DATE_INVALID) return ERR_CERT_DATE_INVALID; - if (cert_status & CERT_STATUS_VALIDITY_TOO_LONG) - return ERR_CERT_VALIDITY_TOO_LONG; // Unknown status. Give it the benefit of the doubt. if (cert_status & CERT_STATUS_UNABLE_TO_CHECK_REVOCATION) diff --git a/net/cert/cert_status_flags_list.h b/net/cert/cert_status_flags_list.h index 932e938cc9b25..c660a7bead2c3 100644 --- a/net/cert/cert_status_flags_list.h +++ b/net/cert/cert_status_flags_list.h @@ -24,7 +24,6 @@ CERT_STATUS_FLAG(WEAK_KEY, 1 << 11) // 1 << 12 was used for CERT_STATUS_WEAK_DH_KEY CERT_STATUS_FLAG(PINNED_KEY_MISSING, 1 << 13) CERT_STATUS_FLAG(NAME_CONSTRAINT_VIOLATION, 1 << 14) -CERT_STATUS_FLAG(VALIDITY_TOO_LONG, 1 << 15) // Bits 16 to 31 are for non-error statuses. CERT_STATUS_FLAG(IS_EV, 1 << 16) diff --git a/net/cert/cert_verify_proc.cc b/net/cert/cert_verify_proc.cc index 981bea008dd12..222ba47f51c98 100644 --- a/net/cert/cert_verify_proc.cc +++ b/net/cert/cert_verify_proc.cc @@ -4,13 +4,10 @@ #include "net/cert/cert_verify_proc.h" -#include - #include "base/basictypes.h" #include "base/metrics/histogram.h" #include "base/sha1.h" #include "base/strings/stringprintf.h" -#include "base/time/time.h" #include "build/build_config.h" #include "net/base/net_errors.h" #include "net/base/net_util.h" @@ -36,6 +33,7 @@ #error Implement certificate verification. #endif + namespace net { namespace { @@ -278,13 +276,6 @@ int CertVerifyProc::Verify(X509Certificate* cert, // now treat it as a warning and do not map it to an error return value. } - // Flag certificates using too long validity periods. - if (verify_result->is_issued_by_known_root && HasTooLongValidity(*cert)) { - verify_result->cert_status |= CERT_STATUS_VALIDITY_TOO_LONG; - if (rv == OK) - rv = MapCertStatusToNetError(verify_result->cert_status); - } - return rv; } @@ -623,41 +614,4 @@ bool CertVerifyProc::HasNameConstraintsViolation( return false; } -// static -bool CertVerifyProc::HasTooLongValidity(const X509Certificate& cert) { - const base::Time& start = cert.valid_start(); - const base::Time& expiry = cert.valid_expiry(); - if (start.is_max() || start.is_null() || expiry.is_max() || - expiry.is_null() || start > expiry) { - return true; - } - - base::Time::Exploded exploded_start; - base::Time::Exploded exploded_expiry; - cert.valid_start().UTCExplode(&exploded_start); - cert.valid_expiry().UTCExplode(&exploded_expiry); - - if (exploded_expiry.year - exploded_start.year > 10) - return true; - int month_diff = (exploded_expiry.year - exploded_start.year) * 12 + - (exploded_expiry.month - exploded_start.month); - - // Add any remainder as a full month. - if (exploded_expiry.day_of_month > exploded_start.day_of_month) - ++month_diff; - - static const base::Time time_2015_04_01 = - base::Time::FromInternalValue(INT64_C(1427871600)); - static const base::Time time_2012_07_01 = - base::Time::FromInternalValue(INT64_C(1341126000)); - static const base::Time time_2019_07_01 = - base::Time::FromInternalValue(INT64_C(1561964400)); - - if (start >= time_2015_04_01) - return month_diff > 39; - if (start >= time_2012_07_01) - return month_diff > 60; - return month_diff > 120 || expiry > time_2019_07_01; -} - } // namespace net diff --git a/net/cert/cert_verify_proc.h b/net/cert/cert_verify_proc.h index f60ed6d923263..95e464e1595b9 100644 --- a/net/cert/cert_verify_proc.h +++ b/net/cert/cert_verify_proc.h @@ -73,7 +73,6 @@ class NET_EXPORT CertVerifyProc private: friend class base::RefCountedThreadSafe; FRIEND_TEST_ALL_PREFIXES(CertVerifyProcTest, DigiNotarCerts); - FRIEND_TEST_ALL_PREFIXES(CertVerifyProcTest, TestHasTooLongValidity); // Performs the actual verification using the desired underlying // cryptographic library. @@ -100,18 +99,6 @@ class NET_EXPORT CertVerifyProc const std::vector& dns_names, const std::vector& ip_addrs); - // The CA/Browser Forum's Baseline Requirements specify maximum validity - // periods (https://cabforum.org/Baseline_Requirements_V1.pdf): - // - // For certificates issued after 1 July 2012: 60 months. - // For certificates issued after 1 April 2015: 39 months. - // - // For certificates issued before the BRs took effect, there were no - // guidelines, but clamp them at a maximum of 10 year validity, with the - // requirement they expire within 7 years after the effective date of the BRs - // (i.e. by 1 July 2019). - static bool HasTooLongValidity(const X509Certificate& cert); - DISALLOW_COPY_AND_ASSIGN(CertVerifyProc); }; diff --git a/net/cert/cert_verify_proc_unittest.cc b/net/cert/cert_verify_proc_unittest.cc index a004f98b5b88c..10a880b42ccc3 100644 --- a/net/cert/cert_verify_proc_unittest.cc +++ b/net/cert/cert_verify_proc_unittest.cc @@ -615,36 +615,16 @@ TEST_F(CertVerifyProcTest, NameConstraintsFailure) { verify_result.cert_status & CERT_STATUS_NAME_CONSTRAINT_VIOLATION); } -TEST_F(CertVerifyProcTest, TestHasTooLongValidity) { - base::FilePath certs_dir = GetTestCertsDirectory(); - - scoped_refptr twitter = - ImportCertFromFile(certs_dir, "twitter-chain.pem"); - EXPECT_FALSE(CertVerifyProc::HasTooLongValidity(*twitter)); - - scoped_refptr eleven_years = - ImportCertFromFile(certs_dir, "11_year_validity.pem"); - EXPECT_TRUE(CertVerifyProc::HasTooLongValidity(*eleven_years)); - - scoped_refptr forty_months = - ImportCertFromFile(certs_dir, "40_months_after_2015_04.pem"); - EXPECT_TRUE(CertVerifyProc::HasTooLongValidity(*forty_months)); - - scoped_refptr sixty_one_months = - ImportCertFromFile(certs_dir, "61_months_after_2012_07.pem"); - EXPECT_TRUE(CertVerifyProc::HasTooLongValidity(*sixty_one_months)); -} - TEST_F(CertVerifyProcTest, TestKnownRoot) { if (!SupportsDetectingKnownRoots()) { - LOG(INFO) << "Skipping this test on this platform."; + LOG(INFO) << "Skipping this test in this platform."; return; } base::FilePath certs_dir = GetTestCertsDirectory(); CertificateList certs = CreateCertificateListFromFile( - certs_dir, "twitter-chain.pem", X509Certificate::FORMAT_AUTO); - ASSERT_EQ(3U, certs.size()); + certs_dir, "satveda.pem", X509Certificate::FORMAT_AUTO); + ASSERT_EQ(2U, certs.size()); X509Certificate::OSCertHandles intermediates; intermediates.push_back(certs[1]->os_cert_handle()); @@ -655,18 +635,20 @@ TEST_F(CertVerifyProcTest, TestKnownRoot) { int flags = 0; CertVerifyResult verify_result; - // This will blow up, May 9th, 2016. Sorry! Please disable and file a bug + // This will blow up, May 24th, 2019. Sorry! Please disable and file a bug // against agl. See also PublicKeyHashes. int error = Verify(cert_chain.get(), - "twitter.com", + "satveda.com", flags, NULL, empty_cert_list_, &verify_result); EXPECT_EQ(OK, error); + EXPECT_EQ(CERT_STATUS_SHA1_SIGNATURE_PRESENT, verify_result.cert_status); EXPECT_TRUE(verify_result.is_issued_by_known_root); } +// The certse.pem certificate has been revoked. crbug.com/259723. TEST_F(CertVerifyProcTest, PublicKeyHashes) { if (!SupportsReturningVerifiedChain()) { LOG(INFO) << "Skipping this test in this platform."; @@ -675,8 +657,8 @@ TEST_F(CertVerifyProcTest, PublicKeyHashes) { base::FilePath certs_dir = GetTestCertsDirectory(); CertificateList certs = CreateCertificateListFromFile( - certs_dir, "twitter-chain.pem", X509Certificate::FORMAT_AUTO); - ASSERT_EQ(3U, certs.size()); + certs_dir, "satveda.pem", X509Certificate::FORMAT_AUTO); + ASSERT_EQ(2U, certs.size()); X509Certificate::OSCertHandles intermediates; intermediates.push_back(certs[1]->os_cert_handle()); @@ -687,16 +669,17 @@ TEST_F(CertVerifyProcTest, PublicKeyHashes) { int flags = 0; CertVerifyResult verify_result; - // This will blow up, May 9th, 2016. Sorry! Please disable and file a bug + // This will blow up, May 24th, 2019. Sorry! Please disable and file a bug // against agl. See also TestKnownRoot. int error = Verify(cert_chain.get(), - "twitter.com", + "satveda.com", flags, NULL, empty_cert_list_, &verify_result); EXPECT_EQ(OK, error); - ASSERT_LE(3U, verify_result.public_key_hashes.size()); + EXPECT_EQ(CERT_STATUS_SHA1_SIGNATURE_PRESENT, verify_result.cert_status); + ASSERT_LE(2U, verify_result.public_key_hashes.size()); HashValueVector sha1_hashes; for (size_t i = 0; i < verify_result.public_key_hashes.size(); ++i) { @@ -704,10 +687,10 @@ TEST_F(CertVerifyProcTest, PublicKeyHashes) { continue; sha1_hashes.push_back(verify_result.public_key_hashes[i]); } - ASSERT_LE(3u, sha1_hashes.size()); + ASSERT_LE(2u, sha1_hashes.size()); - for (size_t i = 0; i < 3; ++i) { - EXPECT_EQ(HexEncode(kTwitterSPKIs[i], base::kSHA1Length), + for (size_t i = 0; i < 2; ++i) { + EXPECT_EQ(HexEncode(kSatvedaSPKIs[i], base::kSHA1Length), HexEncode(sha1_hashes[i].data(), base::kSHA1Length)); } @@ -717,10 +700,10 @@ TEST_F(CertVerifyProcTest, PublicKeyHashes) { continue; sha256_hashes.push_back(verify_result.public_key_hashes[i]); } - ASSERT_LE(3u, sha256_hashes.size()); + ASSERT_LE(2u, sha256_hashes.size()); - for (size_t i = 0; i < 3; ++i) { - EXPECT_EQ(HexEncode(kTwitterSPKIsSHA256[i], crypto::kSHA256Length), + for (size_t i = 0; i < 2; ++i) { + EXPECT_EQ(HexEncode(kSatvedaSPKIsSHA256[i], crypto::kSHA256Length), HexEncode(sha256_hashes[i].data(), crypto::kSHA256Length)); } } @@ -827,7 +810,7 @@ TEST_F(CertVerifyProcTest, IntranetHostsRejected) { } CertificateList cert_list = CreateCertificateListFromFile( - GetTestCertsDirectory(), "reject_intranet_hosts.pem", + GetTestCertsDirectory(), "ok_cert.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, cert_list.size()); scoped_refptr cert(cert_list[0]); diff --git a/net/data/ssl/certificates/11_year_validity.pem b/net/data/ssl/certificates/11_year_validity.pem deleted file mode 100644 index 742da095fbce2..0000000000000 --- a/net/data/ssl/certificates/11_year_validity.pem +++ /dev/null @@ -1,81 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 5 (0x5) - Signature Algorithm: sha256WithRSAEncryption - Issuer: CN=Test Root CA - Validity - Not Before: Oct 30 00:00:00 2014 GMT - Not After : Oct 27 19:26:19 2025 GMT - Subject: CN=xn--wgv71a119e.com - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:bc:20:51:b0:06:00:cb:4d:f0:82:41:9e:a7:df: - e0:15:cf:bc:e5:4b:13:5c:19:51:9d:6c:18:9b:e6: - 77:4e:94:01:64:41:57:33:0d:9b:67:23:2d:8c:22: - 3f:c2:a1:db:d0:ec:20:af:88:95:29:62:0c:74:76: - fc:5b:26:d6:6d:f7:36:cf:b2:ed:64:5d:cc:c0:f6: - 54:3a:c3:89:b1:2a:6f:28:c9:11:05:74:f4:3e:bc: - 1f:e2:e6:04:ab:ad:8f:59:05:f2:03:3d:8e:fb:0c: - 9d:18:c1:12:f8:60:98:b3:e2:a5:ba:00:59:e5:e4: - 19:a1:d9:3b:b1:0a:77:10:e2:72:90:0e:93:50:d8: - b2:f9:39:4b:14:80:4a:18:93:c8:d7:fb:b3:32:0c: - af:c7:f3:d1:d5:48:87:9f:8f:ef:ff:8c:13:61:a5: - 17:32:9d:63:91:c6:93:e9:7c:66:ad:27:b7:9a:fa: - 49:b8:4c:68:c6:ff:18:94:62:4a:f5:03:e4:20:5a: - 7b:96:fd:d6:76:a7:73:9a:e6:ac:1e:9c:83:de:5c: - ce:7d:67:2d:71:ad:33:fc:7e:ba:4a:1d:15:22:32: - 05:9c:65:c5:9d:fa:a5:16:9e:d2:85:fc:c7:a1:cb: - ca:84:d2:bb:8d:11:7b:c3:0c:5f:e5:25:c3:4c:a2: - cb:cb - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:FALSE - X509v3 Subject Key Identifier: - C1:6A:E8:21:0E:C3:F4:D7:73:21:43:E3:B1:FA:65:2C:6F:2D:46:01 - X509v3 Authority Key Identifier: - keyid:CC:56:4D:CF:92:F0:A5:B8:36:08:B0:46:B5:84:E2:4A:00:56:20:57 - - X509v3 Extended Key Usage: - TLS Web Server Authentication, TLS Web Client Authentication - X509v3 Subject Alternative Name: - IP Address:127.0.0.1 - Signature Algorithm: sha256WithRSAEncryption - d0:30:42:a6:35:ce:60:1c:10:56:d0:de:14:d2:8e:6b:97:4b: - 0c:bc:5b:a0:ad:95:99:c1:a3:0b:61:06:e2:7b:7d:4f:94:09: - f1:d6:ca:2f:c9:c6:b3:96:4c:3e:0b:be:15:b2:1d:85:7c:f7: - c4:02:33:e5:c5:1b:99:c5:24:a6:34:e1:19:53:ff:7e:5b:0c: - be:cf:b7:32:86:6c:91:8a:ee:db:8e:ad:44:cf:d7:bc:97:a3: - ff:aa:d0:73:52:21:63:e1:7e:1e:06:58:c1:ac:76:ee:67:a8: - 37:bd:a6:51:3d:53:ec:f5:a9:a3:e0:b1:3b:d3:7e:f7:2d:4e: - 91:b0:77:a5:40:47:98:d9:04:66:83:71:dd:6f:91:f4:e7:6e: - f4:3c:89:a9:65:51:82:ac:43:f0:c0:e7:cf:4f:17:40:dd:10: - 22:d7:e1:37:2d:44:31:d0:d7:d6:73:9f:83:ce:69:bd:50:0e: - e3:12:e4:21:84:da:ca:e0:10:5e:7c:4d:48:d4:72:49:d9:cd: - 35:d3:34:92:d0:4c:a6:33:cc:a5:a4:a0:03:fe:0f:37:1b:f6: - 59:aa:8d:c1:3a:0d:b7:f0:dc:d9:0d:b4:a8:8a:eb:d3:b1:e4: - d0:56:bf:99:6a:f4:a1:09:ff:6e:fd:c0:78:02:03:51:54:ee: - 3a:a7:5e:3f ------BEGIN CERTIFICATE----- -MIIDMDCCAhigAwIBAgIBBTANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxUZXN0 -IFJvb3QgQ0EwHhcNMTQxMDMwMDAwMDAwWhcNMjUxMDI3MTkyNjE5WjAdMRswGQYD -VQQDDBJ4bi0td2d2NzFhMTE5ZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw -ggEKAoIBAQC8IFGwBgDLTfCCQZ6n3+AVz7zlSxNcGVGdbBib5ndOlAFkQVczDZtn -Iy2MIj/CodvQ7CCviJUpYgx0dvxbJtZt9zbPsu1kXczA9lQ6w4mxKm8oyREFdPQ+ -vB/i5gSrrY9ZBfIDPY77DJ0YwRL4YJiz4qW6AFnl5Bmh2TuxCncQ4nKQDpNQ2LL5 -OUsUgEoYk8jX+7MyDK/H89HVSIefj+//jBNhpRcynWORxpPpfGatJ7ea+km4TGjG -/xiUYkr1A+QgWnuW/dZ2p3Oa5qwenIPeXM59Zy1xrTP8frpKHRUiMgWcZcWd+qUW -ntKF/Mehy8qE0ruNEXvDDF/lJcNMosvLAgMBAAGjgYAwfjAMBgNVHRMBAf8EAjAA -MB0GA1UdDgQWBBTBaughDsP013MhQ+Ox+mUsby1GATAfBgNVHSMEGDAWgBTMVk3P -kvCluDYIsEa1hOJKAFYgVzAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw -DwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEA0DBCpjXOYBwQVtDe -FNKOa5dLDLxboK2VmcGjC2EG4nt9T5QJ8dbKL8nGs5ZMPgu+FbIdhXz3xAIz5cUb -mcUkpjThGVP/flsMvs+3MoZskYru246tRM/XvJej/6rQc1IhY+F+HgZYwax27meo -N72mUT1T7PWpo+CxO9N+9y1OkbB3pUBHmNkEZoNx3W+R9Odu9DyJqWVRgqxD8MDn -z08XQN0QItfhNy1EMdDX1nOfg85pvVAO4xLkIYTayuAQXnxNSNRySdnNNdM0ktBM -pjPMpaSgA/4PNxv2WaqNwToNt/Dc2Q20qIrr07Hk0Fa/mWr0oQn/bv3AeAIDUVTu -OqdePw== ------END CERTIFICATE----- diff --git a/net/data/ssl/certificates/40_months_after_2015_04.pem b/net/data/ssl/certificates/40_months_after_2015_04.pem deleted file mode 100644 index 34128a969edad..0000000000000 --- a/net/data/ssl/certificates/40_months_after_2015_04.pem +++ /dev/null @@ -1,81 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 6 (0x6) - Signature Algorithm: sha256WithRSAEncryption - Issuer: CN=Test Root CA - Validity - Not Before: Apr 2 00:00:00 2015 GMT - Not After : Sep 1 00:00:00 2018 GMT - Subject: CN=xn--wgv71a119e.com - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:c1:86:e0:72:bf:df:69:da:78:b1:87:99:03:40: - 19:d1:8b:a9:a3:80:2e:75:25:27:c7:bc:dd:4b:8c: - 8d:11:b1:dd:24:68:12:8d:46:b8:45:19:fc:24:e8: - 2a:15:21:84:9d:a2:08:6b:3e:38:34:3f:29:00:5f: - 04:68:ed:33:4e:35:41:c3:06:54:f3:41:8b:61:83: - 3e:1b:78:59:6b:d2:c3:83:ea:16:99:1f:a7:1c:13: - 34:b5:25:c6:01:6d:34:b5:90:0f:7c:70:f0:ab:18: - 0c:59:a8:7f:ec:20:21:a7:7e:3b:b9:0c:bb:ef:a9: - ce:1b:75:6d:ac:23:c1:56:c1:28:95:70:85:99:a3: - 94:86:ee:c6:45:97:af:29:e1:86:ee:b6:b3:95:97: - 4e:38:9a:03:a8:50:a8:21:ae:48:ae:dd:9a:89:0c: - 81:c6:98:b1:07:5f:55:44:26:6a:3a:cb:8c:d4:07: - 67:71:5d:b1:33:25:2a:ef:f8:af:6b:72:78:f1:9b: - 95:c6:3e:0c:57:77:5f:63:1f:99:1d:b0:a3:ac:f6: - 7d:65:04:7d:aa:f2:99:b9:6f:e7:75:01:34:ec:c5: - 60:b0:c1:bc:c1:f0:d9:10:28:fb:10:ac:ad:3f:ba: - 2f:40:96:c7:59:57:d8:f0:f2:c2:3d:96:bf:86:1f: - 95:55 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:FALSE - X509v3 Subject Key Identifier: - DF:3C:D7:74:E3:7F:2B:EC:C9:44:98:6A:8B:E8:9B:46:23:9B:A4:3C - X509v3 Authority Key Identifier: - keyid:98:AF:9A:51:3C:AB:23:88:17:DB:39:AB:FA:17:91:96:8B:83:C5:F1 - - X509v3 Extended Key Usage: - TLS Web Server Authentication, TLS Web Client Authentication - X509v3 Subject Alternative Name: - IP Address:127.0.0.1 - Signature Algorithm: sha256WithRSAEncryption - 45:0b:b9:a7:3d:d4:a7:c9:0e:d8:a1:df:bf:e0:93:26:c1:da: - 48:ac:70:3b:15:82:30:c9:4d:0f:02:fc:ba:03:24:ab:df:10: - 47:8e:14:ab:e9:20:95:91:56:41:bd:0c:2e:c9:7c:61:d9:69: - 6c:9f:fb:25:eb:34:d4:7a:70:9c:36:ba:64:80:8b:4a:c4:8c: - 23:92:8b:7c:b5:47:e9:f7:37:4c:e0:db:22:ad:67:d0:66:b6: - 9e:01:9e:9f:6e:63:e1:5d:97:90:3f:e0:5c:4c:d5:f5:23:11: - b1:2e:db:c9:79:0f:37:7a:78:67:86:87:14:1b:ab:5b:65:67: - 61:44:ab:43:c5:6e:19:83:99:64:23:d5:61:bc:4c:36:a2:59: - 88:4a:69:18:57:33:c5:38:22:4b:33:64:77:43:81:47:55:f2: - b2:0f:dc:d3:0e:62:4f:19:6b:6b:89:37:33:3b:6a:d5:15:b6: - be:7f:03:ad:88:d2:e2:8e:9e:77:44:39:8e:93:b4:87:87:f6: - 5a:5a:d1:20:94:cc:de:d9:9d:5c:7f:42:dd:81:ce:fa:77:23: - 05:11:bd:8c:2e:06:c3:94:65:cf:8f:9b:db:9a:58:d7:e7:36: - ff:49:4a:9c:99:c7:3a:9a:d1:32:bb:a4:66:d2:80:7d:80:d7: - c9:1d:d7:e7 ------BEGIN CERTIFICATE----- -MIIDMDCCAhigAwIBAgIBBjANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxUZXN0 -IFJvb3QgQ0EwHhcNMTUwNDAyMDAwMDAwWhcNMTgwOTAxMDAwMDAwWjAdMRswGQYD -VQQDDBJ4bi0td2d2NzFhMTE5ZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw -ggEKAoIBAQDBhuByv99p2nixh5kDQBnRi6mjgC51JSfHvN1LjI0Rsd0kaBKNRrhF -Gfwk6CoVIYSdoghrPjg0PykAXwRo7TNONUHDBlTzQYthgz4beFlr0sOD6haZH6cc -EzS1JcYBbTS1kA98cPCrGAxZqH/sICGnfju5DLvvqc4bdW2sI8FWwSiVcIWZo5SG -7sZFl68p4YbutrOVl044mgOoUKghrkiu3ZqJDIHGmLEHX1VEJmo6y4zUB2dxXbEz -JSrv+K9rcnjxm5XGPgxXd19jH5kdsKOs9n1lBH2q8pm5b+d1ATTsxWCwwbzB8NkQ -KPsQrK0/ui9AlsdZV9jw8sI9lr+GH5VVAgMBAAGjgYAwfjAMBgNVHRMBAf8EAjAA -MB0GA1UdDgQWBBTfPNd0438r7MlEmGqL6JtGI5ukPDAfBgNVHSMEGDAWgBSYr5pR -PKsjiBfbOav6F5GWi4PF8TAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw -DwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEARQu5pz3Up8kO2KHf -v+CTJsHaSKxwOxWCMMlNDwL8ugMkq98QR44Uq+kglZFWQb0MLsl8YdlpbJ/7Jes0 -1HpwnDa6ZICLSsSMI5KLfLVH6fc3TODbIq1n0Ga2ngGen25j4V2XkD/gXEzV9SMR -sS7byXkPN3p4Z4aHFBurW2VnYUSrQ8VuGYOZZCPVYbxMNqJZiEppGFczxTgiSzNk -d0OBR1Xysg/c0w5iTxlra4k3Mztq1RW2vn8DrYjS4o6ed0Q5jpO0h4f2WlrRIJTM -3tmdXH9C3YHO+ncjBRG9jC4Gw5Rlz4+b25pY1+c2/0lKnJnHOprRMrukZtKAfYDX -yR3X5w== ------END CERTIFICATE----- diff --git a/net/data/ssl/certificates/61_months_after_2012_07.pem b/net/data/ssl/certificates/61_months_after_2012_07.pem deleted file mode 100644 index 49dc04e53ed31..0000000000000 --- a/net/data/ssl/certificates/61_months_after_2012_07.pem +++ /dev/null @@ -1,81 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 7 (0x7) - Signature Algorithm: sha256WithRSAEncryption - Issuer: CN=Test Root CA - Validity - Not Before: Oct 30 00:00:00 2014 GMT - Not After : Nov 3 19:26:20 2019 GMT - Subject: CN=xn--wgv71a119e.com - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:ca:83:f9:aa:c5:28:81:20:c9:a9:62:66:9b:10: - 75:c1:e7:9a:15:5b:ef:13:ce:c6:d1:aa:be:23:7b: - ca:28:7b:bc:62:27:4a:9d:16:e0:ac:db:07:54:f1: - 3a:79:4f:24:4d:52:2c:35:12:aa:fd:cb:f7:98:5d: - 40:03:56:01:36:b1:1a:34:71:9c:98:5d:76:96:2f: - 91:ca:9f:49:e2:f0:1e:86:fc:d3:66:37:1a:27:b4: - db:4d:b3:ca:85:04:59:b5:2f:35:32:d5:59:a6:31: - f5:85:35:63:88:e5:0a:1b:3b:9a:7c:29:e2:6d:b3: - ed:23:19:36:6d:62:fd:be:77:10:cc:69:2d:32:ce: - 98:59:29:ec:e4:27:e9:c2:ae:86:79:37:76:cb:ba: - ee:86:5f:39:02:25:b2:50:aa:43:7e:77:fe:03:16: - d1:05:56:b5:31:a0:0b:41:88:3e:69:b4:b9:89:70: - d1:e5:7d:a7:77:ed:8d:13:db:20:3b:4b:c0:a0:6e: - 48:61:47:c2:6f:57:f4:4a:ac:bd:28:e3:0f:e4:40: - 3f:a3:05:86:46:1a:95:13:d1:be:76:69:92:d5:6b: - 71:59:1d:a0:fc:b7:4c:9a:e6:2b:f6:82:50:a9:35: - 19:9b:b4:3c:0d:0b:7a:10:0e:3d:84:2f:c3:68:61: - 2f:03 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:FALSE - X509v3 Subject Key Identifier: - 74:7C:2F:56:AE:BF:08:E2:6F:5B:D4:6C:B0:4C:04:3F:11:59:15:0E - X509v3 Authority Key Identifier: - keyid:CC:56:4D:CF:92:F0:A5:B8:36:08:B0:46:B5:84:E2:4A:00:56:20:57 - - X509v3 Extended Key Usage: - TLS Web Server Authentication, TLS Web Client Authentication - X509v3 Subject Alternative Name: - IP Address:127.0.0.1 - Signature Algorithm: sha256WithRSAEncryption - 19:42:64:03:f7:2a:90:ee:82:93:de:69:49:28:32:42:ba:db: - 37:16:0d:db:b3:81:ad:50:a8:b2:f7:20:35:e4:bb:89:7d:f3: - e5:75:7f:3e:bd:41:05:24:eb:5a:94:18:cc:c4:ac:d2:0a:24: - 39:4b:2e:6d:a4:2f:99:6b:19:9e:c8:44:53:3f:15:52:c7:51: - af:37:64:a2:d7:27:74:72:6a:d0:cc:c0:ac:8b:7e:7c:0c:f1: - ee:e9:bf:03:19:20:e3:44:88:56:a2:1f:36:59:7f:35:22:13: - d1:48:a0:7a:59:16:85:df:31:e9:30:ae:df:54:b7:8b:78:a8: - 20:27:5c:cc:0c:8b:43:65:4f:71:41:c2:5b:42:4a:a7:1b:f8: - 44:e3:6b:50:1f:85:0f:e3:30:9a:5f:01:8a:19:80:b1:9d:d8: - 34:c4:54:87:ff:ad:8a:56:d7:3b:9f:13:dd:0c:a5:b7:0d:a9: - a8:66:91:4a:0e:d4:7d:5c:40:39:5a:12:e1:ab:fc:88:9f:b7: - 26:c7:11:f0:1b:7d:2d:29:77:20:97:0c:ea:14:d4:24:13:9f: - 8f:b2:49:eb:3b:2b:79:d3:d2:ef:65:82:d7:75:09:26:61:9b: - ef:45:0d:95:65:1b:42:76:f6:db:98:fa:3f:45:c0:7b:8d:94: - 9a:62:8a:88 ------BEGIN CERTIFICATE----- -MIIDMDCCAhigAwIBAgIBBzANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxUZXN0 -IFJvb3QgQ0EwHhcNMTQxMDMwMDAwMDAwWhcNMTkxMTAzMTkyNjIwWjAdMRswGQYD -VQQDDBJ4bi0td2d2NzFhMTE5ZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw -ggEKAoIBAQDKg/mqxSiBIMmpYmabEHXB55oVW+8TzsbRqr4je8ooe7xiJ0qdFuCs -2wdU8Tp5TyRNUiw1Eqr9y/eYXUADVgE2sRo0cZyYXXaWL5HKn0ni8B6G/NNmNxon -tNtNs8qFBFm1LzUy1VmmMfWFNWOI5QobO5p8KeJts+0jGTZtYv2+dxDMaS0yzphZ -KezkJ+nCroZ5N3bLuu6GXzkCJbJQqkN+d/4DFtEFVrUxoAtBiD5ptLmJcNHlfad3 -7Y0T2yA7S8CgbkhhR8JvV/RKrL0o4w/kQD+jBYZGGpUT0b52aZLVa3FZHaD8t0ya -5iv2glCpNRmbtDwNC3oQDj2EL8NoYS8DAgMBAAGjgYAwfjAMBgNVHRMBAf8EAjAA -MB0GA1UdDgQWBBR0fC9Wrr8I4m9b1GywTAQ/EVkVDjAfBgNVHSMEGDAWgBTMVk3P -kvCluDYIsEa1hOJKAFYgVzAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw -DwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEAGUJkA/cqkO6Ck95p -SSgyQrrbNxYN27OBrVCosvcgNeS7iX3z5XV/Pr1BBSTrWpQYzMSs0gokOUsubaQv -mWsZnshEUz8VUsdRrzdkotcndHJq0MzArIt+fAzx7um/Axkg40SIVqIfNll/NSIT -0UigelkWhd8x6TCu31S3i3ioICdczAyLQ2VPcUHCW0JKpxv4RONrUB+FD+Mwml8B -ihmAsZ3YNMRUh/+tilbXO58T3Qyltw2pqGaRSg7UfVxAOVoS4av8iJ+3JscR8Bt9 -LSl3IJcM6hTUJBOfj7JJ6zsredPS72WC13UJJmGb70UNlWUbQnb225j6P0XAe42U -mmKKiA== ------END CERTIFICATE----- diff --git a/net/data/ssl/certificates/README b/net/data/ssl/certificates/README index c9e1dc5950d3b..5d1faf2602e93 100644 --- a/net/data/ssl/certificates/README +++ b/net/data/ssl/certificates/README @@ -129,8 +129,8 @@ unit tests. - expired_cert.pem - ok_cert.pem - root_ca_cert.pem - These certificates are the common certificates used by the Python test - server for simulating HTTPS connections. + These certificates are the common certificates used by the Python test + server for simulating HTTPS connections. - name_constraint_bad.pem - name_constraint_good.pem @@ -147,12 +147,6 @@ unit tests. - punycodetest.pem : A test self-signed server certificate with punycode name. The common name is "xn--wgv71a119e.com" (日本語.com) -- 40_months_after_2015_04.pem -- 61_months_after_2012_07.pem -- 11_year_validity.pem - Certs to test that the maximum validity durations set by the CA/Browser - Forum Baseline Requirements are enforced. - ===== From net/data/ssl/scripts/generate-weak-test-chains.sh - 2048-rsa-root.pem - {768-rsa,1024-rsa,2048-rsa,prime256v1-ecdsa}-intermediate.pem @@ -258,3 +252,5 @@ unit tests. containing the intermediate, which can be served via a URLRequestFilter. aia-intermediate.der is stored in DER form for convenience, since that is the form expected of certificates discovered via AIA. + + diff --git a/net/data/ssl/certificates/reject_intranet_hosts.pem b/net/data/ssl/certificates/reject_intranet_hosts.pem deleted file mode 100644 index d5040ccf41d96..0000000000000 --- a/net/data/ssl/certificates/reject_intranet_hosts.pem +++ /dev/null @@ -1,69 +0,0 @@ -Certificate: - Data: - Version: 1 (0x0) - Serial Number: 15207369410964614739 (0xd30b6de83cafee53) - Signature Algorithm: sha256WithRSAEncryption - Issuer: C=US, ST=California, L=Mountain View, O=Test CA, CN=127.0.0.1 - Validity - Not Before: Oct 31 19:51:55 2014 GMT - Not After : Oct 30 19:51:55 2017 GMT - Subject: C=US, ST=California, L=Mountain View, O=Test CA, CN=127.0.0.1 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:a0:5c:e4:0d:5d:e4:01:47:d8:8c:06:41:12:f8: - 63:a9:d9:41:3d:e9:75:ad:80:ae:e9:32:2a:d6:6a: - 42:7c:be:f5:1b:02:99:36:a4:dd:02:db:32:36:ab: - ac:8b:c5:78:cb:a2:03:28:db:95:83:56:9a:03:f4: - 37:70:dc:16:56:d9:0a:c6:34:23:f5:58:36:21:c8: - fd:b7:41:1e:2f:85:50:50:d9:76:c0:7d:9e:0d:d7: - ad:df:94:06:c1:b6:a4:c9:ee:61:16:5a:54:c2:1d: - 5e:d9:79:73:4a:21:d0:d3:fe:88:ee:27:3a:5f:e6: - a3:cf:89:44:93:80:64:53:50:36:98:c5:da:1f:87: - 1e:a1:2e:e0:5a:60:c7:80:a7:93:eb:b8:39:33:c3: - d7:e7:2b:bd:9b:48:5d:a4:af:ee:7d:93:5a:d0:9f: - 3b:6d:a8:52:95:ce:d1:bf:0b:a4:60:34:ee:77:80: - 50:35:0d:af:eb:0f:48:69:ab:c7:87:a8:31:44:69: - 9c:21:d6:01:de:61:04:95:a4:85:d0:d6:2e:a6:7c: - d1:fd:61:45:51:fd:bb:bc:be:6b:d3:87:54:50:b8: - 36:f8:f0:0f:a4:07:e0:28:86:13:5b:72:ae:5d:b3: - a2:fa:b7:54:8d:c9:6a:b3:82:88:4f:40:6d:36:1a: - f5:2d - Exponent: 65537 (0x10001) - Signature Algorithm: sha256WithRSAEncryption - 47:0d:cd:15:ec:51:89:2f:e0:d1:4e:04:7a:8e:cf:f5:16:ec: - 11:55:bc:48:92:3b:98:60:ba:f1:97:98:a7:22:bf:9e:00:ac: - 4a:5b:a7:e1:b5:aa:b7:20:c5:fc:85:d5:3f:cf:53:da:60:94: - 75:93:78:87:e0:99:d7:f0:c7:35:e5:6d:82:f7:e7:23:e1:fe: - 88:4d:f0:bf:3b:68:70:61:c1:e8:8d:e1:2a:c9:75:c9:28:66: - 71:79:ff:58:a7:79:c3:1c:97:db:9c:3c:25:84:e0:c2:da:77: - 08:9e:4e:9a:5a:c8:48:83:fe:74:41:73:13:46:c2:69:27:31: - 71:d9:7d:40:46:43:59:6d:cd:54:d8:63:44:5b:5f:22:b9:8e: - 2b:ba:99:d1:38:89:0c:ac:b8:f2:c2:b9:a2:67:ae:3d:56:b6: - c7:c0:cd:4c:e6:70:ce:8e:50:67:3c:93:c5:20:c2:45:66:e5: - 79:7b:29:54:0e:fc:eb:39:75:51:54:5d:fc:69:ad:80:dc:88: - b0:6c:be:0c:e4:9f:e3:81:3c:aa:6b:b6:a6:34:b6:1e:f7:a9: - 8a:3f:bd:3f:2e:e4:da:c0:27:cb:50:fd:8a:7f:44:bd:a3:70: - ad:4e:e4:1b:16:9a:fd:82:4d:55:26:06:ca:c7:25:49:fc:2b: - 9e:54:87:7f ------BEGIN CERTIFICATE----- -MIIDPDCCAiQCCQDTC23oPK/uUzANBgkqhkiG9w0BAQsFADBgMQswCQYDVQQGEwJV -UzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQ -MA4GA1UECgwHVGVzdCBDQTESMBAGA1UEAwwJMTI3LjAuMC4xMB4XDTE0MTAzMTE5 -NTE1NVoXDTE3MTAzMDE5NTE1NVowYDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh -bGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEDAOBgNVBAoMB1Rlc3Qg -Q0ExEjAQBgNVBAMMCTEyNy4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBAKBc5A1d5AFH2IwGQRL4Y6nZQT3pda2ArukyKtZqQny+9RsCmTak3QLb -MjarrIvFeMuiAyjblYNWmgP0N3DcFlbZCsY0I/VYNiHI/bdBHi+FUFDZdsB9ng3X -rd+UBsG2pMnuYRZaVMIdXtl5c0oh0NP+iO4nOl/mo8+JRJOAZFNQNpjF2h+HHqEu -4Fpgx4Cnk+u4OTPD1+crvZtIXaSv7n2TWtCfO22oUpXO0b8LpGA07neAUDUNr+sP -SGmrx4eoMURpnCHWAd5hBJWkhdDWLqZ80f1hRVH9u7y+a9OHVFC4NvjwD6QH4CiG -E1tyrl2zovq3VI3JarOCiE9AbTYa9S0CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA -Rw3NFexRiS/g0U4Eeo7P9RbsEVW8SJI7mGC68ZeYpyK/ngCsSlun4bWqtyDF/IXV -P89T2mCUdZN4h+CZ1/DHNeVtgvfnI+H+iE3wvztocGHB6I3hKsl1yShmcXn/WKd5 -wxyX25w8JYTgwtp3CJ5OmlrISIP+dEFzE0bCaScxcdl9QEZDWW3NVNhjRFtfIrmO -K7qZ0TiJDKy48sK5omeuPVa2x8DNTOZwzo5QZzyTxSDCRWbleXspVA786zl1UVRd -/GmtgNyIsGy+DOSf44E8qmu2pjS2Hvepij+9Py7k2sAny1D9in9EvaNwrU7kGxaa -/YJNVSYGysclSfwrnlSHfw== ------END CERTIFICATE----- diff --git a/net/data/ssl/certificates/satveda.pem b/net/data/ssl/certificates/satveda.pem new file mode 100644 index 0000000000000..4f79703d8c025 --- /dev/null +++ b/net/data/ssl/certificates/satveda.pem @@ -0,0 +1,207 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 21120020890699950 (0x4b088c0ed6c8ae) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, ST=Arizona, L=Scottsdale, O=GoDaddy.com, Inc., OU=http://certificates.godaddy.com/repository, CN=Go Daddy Secure Certification Authority/serialNumber=07969287 + Validity + Not Before: Mar 9 07:19:24 2013 GMT + Not After : May 24 09:39:06 2019 GMT + Subject: OU=Domain Control Validated, CN=www.satveda.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bb:e0:ea:82:8e:50:bf:ba:94:89:e3:f4:dc:b4: + a1:06:91:c1:46:bc:33:37:74:e0:c6:71:e7:f0:09: + ec:d8:8e:ac:48:82:3f:b6:b4:49:80:98:04:04:61: + f7:ea:d2:ad:23:ed:2b:28:54:f2:14:e2:f4:84:88: + 9c:4f:d1:b1:1b:52:98:a6:3e:85:e3:eb:22:df:09: + 86:ff:14:9c:41:46:dd:13:ed:d9:f0:5d:a5:fe:7f: + 6f:31:6b:a0:50:a5:f2:9a:ba:ea:8c:77:4d:1c:64: + 82:7a:ea:f4:54:5b:f3:92:81:5e:5c:b1:04:da:c1: + d6:72:7d:e1:e5:ec:ad:53:ae:3d:14:21:44:2e:67: + f3:a2:c9:7d:9e:0b:98:4d:89:fc:c8:1e:a6:00:45: + 8b:b6:a7:b9:dc:5e:5a:ff:0c:52:c6:92:7e:60:08: + d4:8d:34:6c:00:98:bc:43:e9:7b:e1:92:0b:f5:81: + f0:48:09:18:5a:35:8a:e2:74:f2:9d:da:48:b0:7d: + 02:f8:a4:2b:5e:a0:22:cf:a0:15:9f:fb:ca:4d:8c: + f3:26:cb:62:74:a3:04:6e:e2:38:aa:0a:19:42:e8: + e3:57:a5:d3:97:64:38:31:89:3e:af:93:af:d6:e3: + 60:c1:c3:6a:9c:58:da:16:60:c7:78:01:cf:dc:7c: + e1:11 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Key Usage: critical + Digital Signature, Key Encipherment + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.godaddy.com/gds1-87.crl + + X509v3 Certificate Policies: + Policy: 2.16.840.1.114413.1.7.23.1 + CPS: http://certificates.godaddy.com/repository/ + + Authority Information Access: + OCSP - URI:http://ocsp.godaddy.com/ + CA Issuers - URI:http://certificates.godaddy.com/repository/gd_intermediate.crt + + X509v3 Authority Key Identifier: + keyid:FD:AC:61:32:93:6C:45:D6:E2:EE:85:5F:9A:BA:E7:76:99:68:CC:E7 + + X509v3 Subject Alternative Name: + DNS:www.satveda.com, DNS:satveda.com + X509v3 Subject Key Identifier: + A7:39:2E:DC:0F:22:D5:D6:C6:B1:3B:35:65:3D:0D:B1:75:5B:F7:69 + Signature Algorithm: sha1WithRSAEncryption + 15:a9:fd:28:f6:cd:d1:f0:2d:d7:1c:df:b5:48:5c:c5:2c:44: + 59:ad:ba:3d:bc:08:30:6f:50:a4:9f:0b:05:28:d7:5e:62:87: + f9:5d:24:c0:b1:ce:a1:d2:eb:aa:77:9b:01:21:1b:56:dd:e5: + 32:18:38:44:24:60:76:14:4d:4a:6a:d2:37:8b:64:45:5a:ba: + 4f:bf:b0:33:dd:f6:59:dc:fd:47:a9:3b:4f:29:65:3d:a4:0e: + c7:89:22:48:e7:6b:e4:38:b7:d4:e2:27:1f:22:9c:99:b0:bd: + b4:59:6d:8d:53:30:fa:28:ef:6c:66:b8:af:6c:9b:93:52:72: + 37:b3:2f:c1:bd:73:22:b4:2e:fa:08:fd:0c:95:89:21:eb:01: + 34:82:18:15:12:3c:a1:2c:d9:fc:f3:f9:48:1f:09:44:18:b8: + 7a:5b:57:ea:10:62:59:90:8c:dc:6f:52:f2:2a:a2:da:fc:2d: + b4:8a:fb:11:cd:60:da:f9:dd:31:08:31:04:11:81:4e:4b:8a: + 81:40:70:5e:00:99:87:cb:d6:e0:d8:85:fe:4a:2e:97:99:a0: + 3d:6e:6f:26:a9:4d:e6:97:cb:c5:09:ef:49:24:c7:96:27:7e: + bf:e4:cb:02:f8:00:63:43:7f:ca:05:75:d2:89:7a:f0:25:52: + ac:47:fb:e6 +-----BEGIN CERTIFICATE----- +MIIFRTCCBC2gAwIBAgIHSwiMDtbIrjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE +BhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAY +BgNVBAoTEUdvRGFkZHkuY29tLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydGlm +aWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkxMDAuBgNVBAMTJ0dvIERhZGR5 +IFNlY3VyZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTERMA8GA1UEBRMIMDc5Njky +ODcwHhcNMTMwMzA5MDcxOTI0WhcNMTkwNTI0MDkzOTA2WjA9MSEwHwYDVQQLExhE +b21haW4gQ29udHJvbCBWYWxpZGF0ZWQxGDAWBgNVBAMTD3d3dy5zYXR2ZWRhLmNv +bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALvg6oKOUL+6lInj9Ny0 +oQaRwUa8Mzd04MZx5/AJ7NiOrEiCP7a0SYCYBARh9+rSrSPtKyhU8hTi9ISInE/R +sRtSmKY+hePrIt8Jhv8UnEFG3RPt2fBdpf5/bzFroFCl8pq66ox3TRxkgnrq9FRb +85KBXlyxBNrB1nJ94eXsrVOuPRQhRC5n86LJfZ4LmE2J/MgepgBFi7anudxeWv8M +UsaSfmAI1I00bACYvEPpe+GSC/WB8EgJGFo1iuJ08p3aSLB9AvikK16gIs+gFZ/7 +yk2M8ybLYnSjBG7iOKoKGULo41el05dkODGJPq+Tr9bjYMHDapxY2hZgx3gBz9x8 +4RECAwEAAaOCAbowggG2MA8GA1UdEwEB/wQFMAMBAQAwHQYDVR0lBBYwFAYIKwYB +BQUHAwEGCCsGAQUFBwMCMA4GA1UdDwEB/wQEAwIFoDAzBgNVHR8ELDAqMCigJqAk +hiJodHRwOi8vY3JsLmdvZGFkZHkuY29tL2dkczEtODcuY3JsMFMGA1UdIARMMEow +SAYLYIZIAYb9bQEHFwEwOTA3BggrBgEFBQcCARYraHR0cDovL2NlcnRpZmljYXRl +cy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5LzCBgAYIKwYBBQUHAQEEdDByMCQGCCsG +AQUFBzABhhhodHRwOi8vb2NzcC5nb2RhZGR5LmNvbS8wSgYIKwYBBQUHMAKGPmh0 +dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeS9nZF9pbnRl +cm1lZGlhdGUuY3J0MB8GA1UdIwQYMBaAFP2sYTKTbEXW4u6FX5q653aZaMznMCcG +A1UdEQQgMB6CD3d3dy5zYXR2ZWRhLmNvbYILc2F0dmVkYS5jb20wHQYDVR0OBBYE +FKc5LtwPItXWxrE7NWU9DbF1W/dpMA0GCSqGSIb3DQEBBQUAA4IBAQAVqf0o9s3R +8C3XHN+1SFzFLERZrbo9vAgwb1CknwsFKNdeYof5XSTAsc6h0uuqd5sBIRtW3eUy +GDhEJGB2FE1KatI3i2RFWrpPv7Az3fZZ3P1HqTtPKWU9pA7HiSJI52vkOLfU4icf +IpyZsL20WW2NUzD6KO9sZrivbJuTUnI3sy/BvXMitC76CP0MlYkh6wE0ghgVEjyh +LNn88/lIHwlEGLh6W1fqEGJZkIzcb1LyKqLa/C20ivsRzWDa+d0xCDEEEYFOS4qB +QHBeAJmHy9bg2IX+Si6XmaA9bm8mqU3ml8vFCe9JJMeWJ36/5MsC+ABjQ3/KBXXS +iXrwJVKsR/vm +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 769 (0x301) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=The Go Daddy Group, Inc., OU=Go Daddy Class 2 Certification Authority + Validity + Not Before: Nov 16 01:54:37 2006 GMT + Not After : Nov 16 01:54:37 2026 GMT + Subject: C=US, ST=Arizona, L=Scottsdale, O=GoDaddy.com, Inc., OU=http://certificates.godaddy.com/repository, CN=Go Daddy Secure Certification Authority/serialNumber=07969287 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c4:2d:d5:15:8c:9c:26:4c:ec:32:35:eb:5f:b8: + 59:01:5a:a6:61:81:59:3b:70:63:ab:e3:dc:3d:c7: + 2a:b8:c9:33:d3:79:e4:3a:ed:3c:30:23:84:8e:b3: + 30:14:b6:b2:87:c3:3d:95:54:04:9e:df:99:dd:0b: + 25:1e:21:de:65:29:7e:35:a8:a9:54:eb:f6:f7:32: + 39:d4:26:55:95:ad:ef:fb:fe:58:86:d7:9e:f4:00: + 8d:8c:2a:0c:bd:42:04:ce:a7:3f:04:f6:ee:80:f2: + aa:ef:52:a1:69:66:da:be:1a:ad:5d:da:2c:66:ea: + 1a:6b:bb:e5:1a:51:4a:00:2f:48:c7:98:75:d8:b9: + 29:c8:ee:f8:66:6d:0a:9c:b3:f3:fc:78:7c:a2:f8: + a3:f2:b5:c3:f3:b9:7a:91:c1:a7:e6:25:2e:9c:a8: + ed:12:65:6e:6a:f6:12:44:53:70:30:95:c3:9c:2b: + 58:2b:3d:08:74:4a:f2:be:51:b0:bf:87:d0:4c:27: + 58:6b:b5:35:c5:9d:af:17:31:f8:0b:8f:ee:ad:81: + 36:05:89:08:98:cf:3a:af:25:87:c0:49:ea:a7:fd: + 67:f7:45:8e:97:cc:14:39:e2:36:85:b5:7e:1a:37: + fd:16:f6:71:11:9a:74:30:16:fe:13:94:a3:3f:84: + 0d:4f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + FD:AC:61:32:93:6C:45:D6:E2:EE:85:5F:9A:BA:E7:76:99:68:CC:E7 + X509v3 Authority Key Identifier: + keyid:D2:C4:B0:D2:91:D4:4C:11:71:B3:61:CB:3D:A1:FE:DD:A8:6A:D4:E3 + + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + Authority Information Access: + OCSP - URI:http://ocsp.godaddy.com + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://certificates.godaddy.com/repository/gdroot.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://certificates.godaddy.com/repository + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Signature Algorithm: sha1WithRSAEncryption + d2:86:c0:ec:bd:f9:a1:b6:67:ee:66:0b:a2:06:3a:04:50:8e: + 15:72:ac:4a:74:95:53:cb:37:cb:44:49:ef:07:90:6b:33:d9: + 96:f0:94:56:a5:13:30:05:3c:85:32:21:7b:c9:c7:0a:a8:24: + a4:90:de:46:d3:25:23:14:03:67:c2:10:d6:6f:0f:5d:7b:7a: + cc:9f:c5:58:2a:c1:c4:9e:21:a8:5a:f3:ac:a4:46:f3:9e:e4: + 63:cb:2f:90:a4:29:29:01:d9:72:2c:29:df:37:01:27:bc:4f: + ee:68:d3:21:8f:c0:b3:e4:f5:09:ed:d2:10:aa:53:b4:be:f0: + cc:59:0b:d6:3b:96:1c:95:24:49:df:ce:ec:fd:a7:48:91:14: + 45:0e:3a:36:6f:da:45:b3:45:a2:41:c9:d4:d7:44:4e:3e:b9: + 74:76:d5:a2:13:55:2c:c6:87:a3:b5:99:ac:06:84:87:7f:75: + 06:fc:bf:14:4c:0e:cc:6e:c4:df:3d:b7:12:71:f4:e8:f1:51: + 40:22:28:49:e0:1d:4b:87:a8:34:cc:06:a2:dd:12:5a:d1:86: + 36:64:03:35:6f:6f:77:6e:eb:f2:85:50:98:5e:ab:03:53:ad: + 91:23:63:1f:16:9c:cd:b9:b2:05:63:3a:e1:f4:68:1b:17:05: + 35:95:53:ee +-----BEGIN CERTIFICATE----- +MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVMx +ITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g +RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMTYw +MTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UECBMH +QXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5j +b20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j +b20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTtwY6vj3D3H +KrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqVTr9vcyOdQm +VZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aLGbqGmu75RpR +SgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo7RJlbmr2EkRT +cDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgWJCJjPOq8lh8BJ +6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAwEAAaOCATIwggEu +MB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVHSMEGDAWgBTSxLDS +kdRMEXGzYcs9of7dqGrU4zASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEB +BCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWRkeS5jb20wRgYDVR0f +BD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBv +c2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVHSAAMDgwNgYIKwYBBQUH +AgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTAO +BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBANKGwOy9+aG2Z+5mC6IG +OgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPIUyIXvJxwqoJKSQ3kbTJSMU +A2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL5CkKSkB2XIsKd83ASe8T+5o +0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9p0iRFEUOOjZv2kWzRaJBydTX +RE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsxuxN89txJx9OjxUUAiKEngHUuH +qDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZEjYx8WnM25sgVjOuH0aBsXBTWV +U+4= +-----END CERTIFICATE----- diff --git a/net/data/ssl/certificates/twitter-chain.pem b/net/data/ssl/certificates/twitter-chain.pem deleted file mode 100644 index 0d66f4abc12d2..0000000000000 --- a/net/data/ssl/certificates/twitter-chain.pem +++ /dev/null @@ -1,302 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 1a:c8:5e:b7:ae:c3:51:3c:d8:0d:85:38:5e:cf:d2:08 - Signature Algorithm: sha256WithRSAEncryption - Issuer: C=US, O=Symantec Corporation, OU=Symantec Trust Network, CN=Symantec Class 3 EV SSL CA - G3 - Validity - Not Before: Sep 10 00:00:00 2014 GMT - Not After : May 9 23:59:59 2016 GMT - Subject: 1.3.6.1.4.1.311.60.2.1.3=US/1.3.6.1.4.1.311.60.2.1.2=Delaware/businessCategory=Private Organization/serialNumber=4337446, C=US/postalCode=94103-1307, ST=California, L=San Francisco/street=1355 Market St, O=Twitter, Inc., OU=Twitter Security, CN=twitter.com - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:e3:ac:59:34:07:dc:11:f8:1c:ca:b3:0f:93:44: - 8a:54:34:76:90:6a:c0:22:00:be:95:9a:da:58:3c: - 6c:38:31:a2:a2:1f:3b:64:e2:9d:e0:f5:c2:ab:07: - 90:5b:7c:fe:f9:88:8c:6a:9d:69:3b:e0:23:65:b7: - 11:d6:e8:88:d6:3e:6d:8b:ed:ca:ea:58:0b:fe:4d: - bf:2a:95:ca:bb:21:bb:ce:d6:e2:10:02:11:21:68: - 26:f7:92:7e:9c:a3:80:b1:82:d7:e5:a6:a0:86:47: - 42:1a:c6:5b:04:d9:c3:b5:b2:9b:38:d4:a1:6d:3b: - bd:d8:05:f0:51:9b:bd:95:77:7f:e9:02:8e:60:a3: - 7a:65:20:52:23:db:8d:01:27:24:c2:00:66:0d:14: - 66:b3:52:2b:cc:6b:5b:a5:44:2f:e2:40:6d:da:21: - a1:92:5a:57:12:d3:47:01:ef:e9:df:af:c6:91:8c: - 21:af:77:65:13:36:1c:63:7a:2d:05:e6:63:c5:0b: - d8:39:e9:ac:f2:3b:ff:9d:c5:a7:46:0a:6e:1a:66: - 10:1e:4a:e7:ba:c7:89:79:1f:ae:f1:f3:84:03:ca: - e7:50:8a:19:63:bf:3c:20:10:78:c5:f4:53:3c:7d: - 5e:0d:af:96:70:89:92:b9:7f:9a:19:0c:f6:78:6a: - 8f:73 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Subject Alternative Name: - DNS:twitter.com, DNS:www.twitter.com - X509v3 Basic Constraints: - CA:FALSE - X509v3 Key Usage: critical - Digital Signature, Key Encipherment - X509v3 Extended Key Usage: - TLS Web Server Authentication, TLS Web Client Authentication - X509v3 Certificate Policies: - Policy: 2.16.840.1.113733.1.7.23.6 - CPS: https://d.symcb.com/cps - User Notice: - Explicit Text: https://d.symcb.com/rpa - - X509v3 Authority Key Identifier: - keyid:01:59:AB:E7:DD:3A:0B:59:A6:64:63:D6:CF:20:07:57:D5:91:E7:6A - - X509v3 CRL Distribution Points: - - Full Name: - URI:http://sr.symcb.com/sr.crl - - Authority Information Access: - OCSP - URI:http://sr.symcd.com - CA Issuers - URI:http://sr.symcb.com/sr.crt - - Signature Algorithm: sha256WithRSAEncryption - d1:53:68:e9:d6:20:d0:56:7a:10:80:b8:e9:7e:00:c9:9e:d5: - 35:4a:a2:d2:a0:16:8a:e2:fb:eb:96:88:77:c2:6e:35:f4:a7: - a9:aa:dc:35:7b:c6:7d:5e:3c:f6:c9:5b:a0:d1:58:ae:7d:96: - e7:54:02:5c:69:1b:56:92:26:ad:06:2c:c1:5a:ff:59:f3:8a: - 8c:94:32:0d:1a:42:d1:6e:bc:1c:bd:a8:c6:08:01:1b:73:17: - 93:28:30:ae:ce:4d:4e:2d:4b:bf:22:af:9a:61:32:7a:a8:68: - 25:19:3c:6d:fb:67:cc:29:3f:5b:f5:d1:af:4c:bf:67:a3:60: - c4:dd:b0:fb:83:55:6d:b5:2c:a9:7d:34:ad:b0:08:c7:2c:f0: - cb:4c:d8:2b:79:f4:e9:da:7f:6e:c0:de:55:7c:d6:d6:47:cf: - c4:90:ef:4f:be:eb:c9:3d:05:71:6b:5e:c7:36:8d:4f:0c:3c: - 47:83:a5:11:88:22:f8:46:e0:f8:9b:1a:fe:e9:a2:df:90:81: - 10:71:f3:97:9c:b7:69:60:77:20:d6:87:85:ee:5a:77:d2:92: - ec:d9:5d:1f:31:3b:3a:e2:5b:35:d1:92:36:db:44:d4:79:d9: - 6c:03:24:87:5d:c3:86:c6:10:e2:ea:65:7c:cf:b8:ef:c2:31: - 02:55:72:12 ------BEGIN CERTIFICATE----- -MIIFjTCCBHWgAwIBAgIQGshet67DUTzYDYU4Xs/SCDANBgkqhkiG9w0BAQsFADB3 -MQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAd -BgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMTH1N5bWFudGVj -IENsYXNzIDMgRVYgU1NMIENBIC0gRzMwHhcNMTQwOTEwMDAwMDAwWhcNMTYwNTA5 -MjM1OTU5WjCCARIxEzARBgsrBgEEAYI3PAIBAxMCVVMxGTAXBgsrBgEEAYI3PAIB -AgwIRGVsYXdhcmUxHTAbBgNVBA8TFFByaXZhdGUgT3JnYW5pemF0aW9uMRAwDgYD -VQQFEwc0MzM3NDQ2MQswCQYDVQQGEwJVUzETMBEGA1UEEQwKOTQxMDMtMTMwNzET -MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEXMBUG -A1UECQwOMTM1NSBNYXJrZXQgU3QxFjAUBgNVBAoMDVR3aXR0ZXIsIEluYy4xGTAX -BgNVBAsMEFR3aXR0ZXIgU2VjdXJpdHkxFDASBgNVBAMMC3R3aXR0ZXIuY29tMIIB -IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA46xZNAfcEfgcyrMPk0SKVDR2 -kGrAIgC+lZraWDxsODGioh87ZOKd4PXCqweQW3z++YiMap1pO+AjZbcR1uiI1j5t -i+3K6lgL/k2/KpXKuyG7ztbiEAIRIWgm95J+nKOAsYLX5aaghkdCGsZbBNnDtbKb -ONShbTu92AXwUZu9lXd/6QKOYKN6ZSBSI9uNASckwgBmDRRms1IrzGtbpUQv4kBt -2iGhklpXEtNHAe/p36/GkYwhr3dlEzYcY3otBeZjxQvYOems8jv/ncWnRgpuGmYQ -HkrnuseJeR+u8fOEA8rnUIoZY788IBB4xfRTPH1eDa+WcImSuX+aGQz2eGqPcwID -AQABo4IBdjCCAXIwJwYDVR0RBCAwHoILdHdpdHRlci5jb22CD3d3dy50d2l0dGVy -LmNvbTAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEF -BQcDAQYIKwYBBQUHAwIwZgYDVR0gBF8wXTBbBgtghkgBhvhFAQcXBjBMMCMGCCsG -AQUFBwIBFhdodHRwczovL2Quc3ltY2IuY29tL2NwczAlBggrBgEFBQcCAjAZGhdo -dHRwczovL2Quc3ltY2IuY29tL3JwYTAfBgNVHSMEGDAWgBQBWavn3ToLWaZkY9bP -IAdX1ZHnajArBgNVHR8EJDAiMCCgHqAchhpodHRwOi8vc3Iuc3ltY2IuY29tL3Ny -LmNybDBXBggrBgEFBQcBAQRLMEkwHwYIKwYBBQUHMAGGE2h0dHA6Ly9zci5zeW1j -ZC5jb20wJgYIKwYBBQUHMAKGGmh0dHA6Ly9zci5zeW1jYi5jb20vc3IuY3J0MA0G -CSqGSIb3DQEBCwUAA4IBAQDRU2jp1iDQVnoQgLjpfgDJntU1SqLSoBaK4vvrloh3 -wm419Kepqtw1e8Z9Xjz2yVug0ViufZbnVAJcaRtWkiatBizBWv9Z84qMlDINGkLR -brwcvajGCAEbcxeTKDCuzk1OLUu/Iq+aYTJ6qGglGTxt+2fMKT9b9dGvTL9no2DE -3bD7g1VttSypfTStsAjHLPDLTNgrefTp2n9uwN5VfNbWR8/EkO9PvuvJPQVxa17H -No1PDDxHg6URiCL4RuD4mxr+6aLfkIEQcfOXnLdpYHcg1oeF7lp30pLs2V0fMTs6 -4ls10ZI220TUedlsAySHXcOGxhDi6mV8z7jvwjECVXIS ------END CERTIFICATE----- -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 7e:e1:4a:6f:6f:ef:f2:d3:7f:3f:ad:65:4d:3a:da:b4 - Signature Algorithm: sha256WithRSAEncryption - Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5 - Validity - Not Before: Oct 31 00:00:00 2013 GMT - Not After : Oct 30 23:59:59 2023 GMT - Subject: C=US, O=Symantec Corporation, OU=Symantec Trust Network, CN=Symantec Class 3 EV SSL CA - G3 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:d8:a1:65:74:23:e8:2b:64:e2:32:d7:33:37:3d: - 8e:f5:34:16:48:dd:4f:7f:87:1c:f8:44:23:13:8e: - fb:11:d8:44:5a:18:71:8e:60:16:26:92:9b:fd:17: - 0b:e1:71:70:42:fe:bf:fa:1c:c0:aa:a3:a7:b5:71: - e8:ff:18:83:f6:df:10:0a:13:62:c8:3d:9c:a7:de: - 2e:3f:0c:d9:1d:e7:2e:fb:2a:ce:c8:9a:7f:87:bf: - d8:4c:04:15:32:c9:d1:cc:95:71:a0:4e:28:4f:84: - d9:35:fb:e3:86:6f:94:53:e6:72:8a:63:67:2e:be: - 69:f6:f7:6e:8e:9c:60:04:eb:29:fa:c4:47:42:d2: - 78:98:e3:ec:0b:a5:92:dc:b7:9a:bd:80:64:2b:38: - 7c:38:09:5b:66:f6:2d:95:7a:86:b2:34:2e:85:9e: - 90:0e:5f:b7:5d:a4:51:72:46:70:13:bf:67:f2:b6: - a7:4d:14:1e:6c:b9:53:ee:23:1a:4e:8d:48:55:43: - 41:b1:89:75:6a:40:28:c5:7d:dd:d2:6e:d2:02:19: - 2f:7b:24:94:4b:eb:f1:1a:a9:9b:e3:23:9a:ea:fa: - 33:ab:0a:2c:b7:f4:60:08:dd:9f:1c:cd:dd:2d:01: - 66:80:af:b3:2f:29:1d:23:b8:8a:e1:a1:70:07:0c: - 34:0f - Exponent: 65537 (0x10001) - X509v3 extensions: - Authority Information Access: - OCSP - URI:http://s2.symcb.com - - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - X509v3 Certificate Policies: - Policy: X509v3 Any Policy - CPS: http://www.symauth.com/cps - User Notice: - Explicit Text: http://www.symauth.com/rpa - - X509v3 CRL Distribution Points: - - Full Name: - URI:http://s1.symcb.com/pca3-g5.crl - - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Subject Alternative Name: - DirName:/CN=SymantecPKI-1-533 - X509v3 Subject Key Identifier: - 01:59:AB:E7:DD:3A:0B:59:A6:64:63:D6:CF:20:07:57:D5:91:E7:6A - X509v3 Authority Key Identifier: - keyid:7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33 - - Signature Algorithm: sha256WithRSAEncryption - 42:01:55:7b:d0:16:1a:5d:58:e8:bb:9b:a8:4d:d7:f3:d7:eb: - 13:94:86:d6:7f:21:0b:47:bc:57:9b:92:5d:4f:05:9f:38:a4: - 10:7c:cf:83:be:06:43:46:8d:08:bc:6a:d7:10:a6:fa:ab:af: - 2f:61:a8:63:f2:65:df:7f:4c:88:12:88:4f:b3:69:d9:ff:27: - c0:0a:97:91:8f:56:fb:89:c4:a8:bb:92:2d:1b:73:b0:c6:ab: - 36:f4:96:6c:20:08:ef:0a:1e:66:24:45:4f:67:00:40:c8:07: - 54:74:33:3b:a6:ad:bb:23:9f:66:ed:a2:44:70:34:fb:0e:ea: - 01:fd:cf:78:74:df:a7:ad:55:b7:5f:4d:f6:d6:3f:e0:86:ce: - 24:c7:42:a9:13:14:44:35:4b:b6:df:c9:60:ac:0c:7f:d9:93: - 21:4b:ee:9c:e4:49:02:98:d3:60:7b:5c:bc:d5:30:2f:07:ce: - 44:42:c4:0b:99:fe:e6:9f:fc:b0:78:86:51:6d:d1:2c:9d:c6: - 96:fb:85:82:bb:04:2f:f7:62:80:ef:62:da:7f:f6:0e:ac:90: - b8:56:bd:79:3f:f2:80:6e:a3:d9:b9:0f:5d:3a:07:1d:91:93: - 86:4b:29:4c:e1:dc:b5:e1:e0:33:9d:b3:cb:36:91:4b:fe:a1: - b4:ee:f0:f9 ------BEGIN CERTIFICATE----- -MIIFKzCCBBOgAwIBAgIQfuFKb2/v8tN/P61lTTratDANBgkqhkiG9w0BAQsFADCB -yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL -ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp -U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW -ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5IC0gRzUwHhcNMTMxMDMxMDAwMDAwWhcNMjMxMDMwMjM1OTU5WjB3MQsw -CQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAdBgNV -BAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMTH1N5bWFudGVjIENs -YXNzIDMgRVYgU1NMIENBIC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQDYoWV0I+grZOIy1zM3PY71NBZI3U9/hxz4RCMTjvsR2ERaGHGOYBYmkpv9 -FwvhcXBC/r/6HMCqo6e1cej/GIP23xAKE2LIPZyn3i4/DNkd5y77Ks7Imn+Hv9hM -BBUyydHMlXGgTihPhNk1++OGb5RT5nKKY2cuvmn2926OnGAE6yn6xEdC0niY4+wL -pZLct5q9gGQrOHw4CVtm9i2VeoayNC6FnpAOX7ddpFFyRnATv2fytqdNFB5suVPu -IxpOjUhVQ0GxiXVqQCjFfd3SbtICGS97JJRL6/EaqZvjI5rq+jOrCiy39GAI3Z8c -zd0tAWaAr7MvKR0juIrhoXAHDDQPAgMBAAGjggFdMIIBWTAvBggrBgEFBQcBAQQj -MCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9zMi5zeW1jYi5jb20wEgYDVR0TAQH/BAgw -BgEB/wIBADBlBgNVHSAEXjBcMFoGBFUdIAAwUjAmBggrBgEFBQcCARYaaHR0cDov -L3d3dy5zeW1hdXRoLmNvbS9jcHMwKAYIKwYBBQUHAgIwHBoaaHR0cDovL3d3dy5z -eW1hdXRoLmNvbS9ycGEwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL3MxLnN5bWNi -LmNvbS9wY2EzLWc1LmNybDAOBgNVHQ8BAf8EBAMCAQYwKQYDVR0RBCIwIKQeMBwx -GjAYBgNVBAMTEVN5bWFudGVjUEtJLTEtNTMzMB0GA1UdDgQWBBQBWavn3ToLWaZk -Y9bPIAdX1ZHnajAfBgNVHSMEGDAWgBR/02Wnwt3su/AwCfNDOfoCrzMxMzANBgkq -hkiG9w0BAQsFAAOCAQEAQgFVe9AWGl1Y6LubqE3X89frE5SG1n8hC0e8V5uSXU8F -nzikEHzPg74GQ0aNCLxq1xCm+quvL2GoY/Jl339MiBKIT7Np2f8nwAqXkY9W+4nE -qLuSLRtzsMarNvSWbCAI7woeZiRFT2cAQMgHVHQzO6atuyOfZu2iRHA0+w7qAf3P -eHTfp61Vt19N9tY/4IbOJMdCqRMURDVLtt/JYKwMf9mTIUvunORJApjTYHtcvNUw -LwfORELEC5n+5p/8sHiGUW3RLJ3GlvuFgrsEL/digO9i2n/2DqyQuFa9eT/ygG6j -2bkPXToHHZGThkspTOHcteHgM52zyzaRS/6htO7w+Q== ------END CERTIFICATE----- -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 18:da:d1:9e:26:7d:e8:bb:4a:21:58:cd:cc:6b:3b:4a - Signature Algorithm: sha1WithRSAEncryption - Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5 - Validity - Not Before: Nov 8 00:00:00 2006 GMT - Not After : Jul 16 23:59:59 2036 GMT - Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:af:24:08:08:29:7a:35:9e:60:0c:aa:e7:4b:3b: - 4e:dc:7c:bc:3c:45:1c:bb:2b:e0:fe:29:02:f9:57: - 08:a3:64:85:15:27:f5:f1:ad:c8:31:89:5d:22:e8: - 2a:aa:a6:42:b3:8f:f8:b9:55:b7:b1:b7:4b:b3:fe: - 8f:7e:07:57:ec:ef:43:db:66:62:15:61:cf:60:0d: - a4:d8:de:f8:e0:c3:62:08:3d:54:13:eb:49:ca:59: - 54:85:26:e5:2b:8f:1b:9f:eb:f5:a1:91:c2:33:49: - d8:43:63:6a:52:4b:d2:8f:e8:70:51:4d:d1:89:69: - 7b:c7:70:f6:b3:dc:12:74:db:7b:5d:4b:56:d3:96: - bf:15:77:a1:b0:f4:a2:25:f2:af:1c:92:67:18:e5: - f4:06:04:ef:90:b9:e4:00:e4:dd:3a:b5:19:ff:02: - ba:f4:3c:ee:e0:8b:eb:37:8b:ec:f4:d7:ac:f2:f6: - f0:3d:af:dd:75:91:33:19:1d:1c:40:cb:74:24:19: - 21:93:d9:14:fe:ac:2a:52:c7:8f:d5:04:49:e4:8d: - 63:47:88:3c:69:83:cb:fe:47:bd:2b:7e:4f:c5:95: - ae:0e:9d:d4:d1:43:c0:67:73:e3:14:08:7e:e5:3f: - 9f:73:b8:33:0a:cf:5d:3f:34:87:96:8a:ee:53:e8: - 25:15 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - 1.3.6.1.5.5.7.1.12: - 0_.].[0Y0W0U..image/gif0!0.0...+..............k...j.H.,{..0%.#http://logo.verisign.com/vslogo.gif - X509v3 Subject Key Identifier: - 7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33 - Signature Algorithm: sha1WithRSAEncryption - 93:24:4a:30:5f:62:cf:d8:1a:98:2f:3d:ea:dc:99:2d:bd:77: - f6:a5:79:22:38:ec:c4:a7:a0:78:12:ad:62:0e:45:70:64:c5: - e7:97:66:2d:98:09:7e:5f:af:d6:cc:28:65:f2:01:aa:08:1a: - 47:de:f9:f9:7c:92:5a:08:69:20:0d:d9:3e:6d:6e:3c:0d:6e: - d8:e6:06:91:40:18:b9:f8:c1:ed:df:db:41:aa:e0:96:20:c9: - cd:64:15:38:81:c9:94:ee:a2:84:29:0b:13:6f:8e:db:0c:dd: - 25:02:db:a4:8b:19:44:d2:41:7a:05:69:4a:58:4f:60:ca:7e: - 82:6a:0b:02:aa:25:17:39:b5:db:7f:e7:84:65:2a:95:8a:bd: - 86:de:5e:81:16:83:2d:10:cc:de:fd:a8:82:2a:6d:28:1f:0d: - 0b:c4:e5:e7:1a:26:19:e1:f4:11:6f:10:b5:95:fc:e7:42:05: - 32:db:ce:9d:51:5e:28:b6:9e:85:d3:5b:ef:a5:7d:45:40:72: - 8e:b7:0e:6b:0e:06:fb:33:35:48:71:b8:9d:27:8b:c4:65:5f: - 0d:86:76:9c:44:7a:f6:95:5c:f6:5d:32:08:33:a4:54:b6:18: - 3f:68:5c:f2:42:4a:85:38:54:83:5f:d1:e8:2c:f2:ac:11:d6: - a8:ed:63:6a ------BEGIN CERTIFICATE----- -MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB -yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL -ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp -U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW -ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL -MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW -ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln -biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp -U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y -aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 -nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex -t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz -SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG -BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ -rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ -NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E -BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH -BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy -aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv -MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE -p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y -5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK -WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ -4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N -hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq ------END CERTIFICATE----- diff --git a/net/data/ssl/scripts/generate-test-certs.sh b/net/data/ssl/scripts/generate-test-certs.sh index c94ca6c3fbe2c..d62bb988a5ddc 100755 --- a/net/data/ssl/scripts/generate-test-certs.sh +++ b/net/data/ssl/scripts/generate-test-certs.sh @@ -124,51 +124,7 @@ try openssl req -x509 -days 3650 -extensions req_san_sanity \ SUBJECT_NAME="req_punycode_dn" \ try openssl req -x509 -days 3650 -extensions req_punycode \ -config ../scripts/ee.cnf -newkey rsa:2048 -text \ - -out ../certificates/punycodetest.pem - -## Reject intranet hostnames in "publicly" trusted certs -# 365 * 3 = 1095 -SUBJECT_NAME="req_dn" \ - try openssl req -x509 -days 1095 \ - -config ../scripts/ee.cnf -newkey rsa:2048 -text \ - -out ../certificates/reject_intranet_hosts.pem - -## Validity too long -# 365 * 11 = 4015 -try openssl req -config ../scripts/ee.cnf \ - -newkey rsa:2048 -text -out ../certificates/11_year_validity.req -CA_COMMON_NAME="Test Root CA" \ - try openssl ca \ - -batch \ - -extensions user_cert \ - -startdate 141030000000Z \ - -days 4015 \ - -in ../certificates/11_year_validity.req \ - -out ../certificates/11_year_validity.pem \ - -config ca.cnf -try openssl req -config ../scripts/ee.cnf \ - -newkey rsa:2048 -text -out ../certificates/40_months_after_2015_04.req -CA_COMMON_NAME="Test Root CA" \ - try openssl ca \ - -batch \ - -extensions user_cert \ - -startdate 150402000000Z \ - -enddate 180901000000Z \ - -in ../certificates/40_months_after_2015_04.req \ - -out ../certificates/40_months_after_2015_04.pem \ - -config ca.cnf -try openssl req -config ../scripts/ee.cnf \ - -newkey rsa:2048 -text -out ../certificates/61_months_after_2012_07.req -# 30 * 61 = 1830 -CA_COMMON_NAME="Test Root CA" \ - try openssl ca \ - -batch \ - -extensions user_cert \ - -startdate 141030000000Z \ - -days 1830 \ - -in ../certificates/61_months_after_2012_07.req \ - -out ../certificates/61_months_after_2012_07.pem \ - -config ca.cnf + -out ../certificates/punycodetest.pem # Regenerate CRLSets ## Block a leaf cert directly by SPKI diff --git a/net/http/disk_cache_based_quic_server_info.cc b/net/http/disk_cache_based_quic_server_info.cc index 4ed2bfa2b4380..148df3f68b2a2 100644 --- a/net/http/disk_cache_based_quic_server_info.cc +++ b/net/http/disk_cache_based_quic_server_info.cc @@ -6,6 +6,7 @@ #include "base/bind.h" #include "base/callback.h" +#include "base/callback_helpers.h" #include "base/logging.h" #include "base/metrics/histogram.h" #include "net/base/completion_callback.h" @@ -56,6 +57,7 @@ DiskCacheBasedQuicServerInfo::DiskCacheBasedQuicServerInfo( http_cache_(http_cache), backend_(NULL), entry_(NULL), + last_failure_(NO_FAILURE), weak_factory_(this) { io_callback_ = base::Bind(&DiskCacheBasedQuicServerInfo::OnIOComplete, @@ -66,6 +68,7 @@ DiskCacheBasedQuicServerInfo::DiskCacheBasedQuicServerInfo( void DiskCacheBasedQuicServerInfo::Start() { DCHECK(CalledOnValidThread()); DCHECK_EQ(GET_BACKEND, state_); + DCHECK_EQ(last_failure_, NO_FAILURE); RecordQuicServerInfoStatus(QUIC_SERVER_INFO_START); load_start_time_ = base::TimeTicks::Now(); DoLoop(OK); @@ -77,18 +80,19 @@ int DiskCacheBasedQuicServerInfo::WaitForDataReady( DCHECK_NE(GET_BACKEND, state_); RecordQuicServerInfoStatus(QUIC_SERVER_INFO_WAIT_FOR_DATA_READY); - if (ready_) + if (ready_) { + RecordLastFailure(); return OK; + } if (!callback.is_null()) { // Prevent a new callback for WaitForDataReady overwriting an existing - // pending callback (|user_callback_|). - // TODO(rtenneti): Rename user_callback_ as wait_for_ready_callback_. - if (!user_callback_.is_null()) { + // pending callback (|wait_for_ready_callback_|). + if (!wait_for_ready_callback_.is_null()) { RecordQuicServerInfoFailure(WAIT_FOR_DATA_READY_INVALID_ARGUMENT_FAILURE); return ERR_INVALID_ARGUMENT; } - user_callback_ = callback; + wait_for_ready_callback_ = callback; } return ERR_IO_PENDING; @@ -98,8 +102,10 @@ void DiskCacheBasedQuicServerInfo::CancelWaitForDataReadyCallback() { DCHECK(CalledOnValidThread()); RecordQuicServerInfoStatus(QUIC_SERVER_INFO_WAIT_FOR_DATA_READY_CANCEL); - if (!user_callback_.is_null()) - user_callback_.Reset(); + if (!wait_for_ready_callback_.is_null()) { + RecordLastFailure(); + wait_for_ready_callback_.Reset(); + } } bool DiskCacheBasedQuicServerInfo::IsDataReady() { @@ -131,10 +137,10 @@ void DiskCacheBasedQuicServerInfo::Persist() { void DiskCacheBasedQuicServerInfo::PersistInternal() { DCHECK(CalledOnValidThread()); DCHECK_NE(GET_BACKEND, state_); - DCHECK(new_data_.empty()); CHECK(ready_); - DCHECK(user_callback_.is_null()); + DCHECK(wait_for_ready_callback_.is_null()); + if (pending_write_data_.empty()) { new_data_ = Serialize(); } else { @@ -166,7 +172,7 @@ void DiskCacheBasedQuicServerInfo::OnExternalCacheHit() { } DiskCacheBasedQuicServerInfo::~DiskCacheBasedQuicServerInfo() { - DCHECK(user_callback_.is_null()); + DCHECK(wait_for_ready_callback_.is_null()); if (entry_) entry_->Close(); } @@ -181,10 +187,9 @@ void DiskCacheBasedQuicServerInfo::OnIOComplete(CacheOperationDataShim* unused, rv = DoLoop(rv); if (rv == ERR_IO_PENDING) return; - if (!user_callback_.is_null()) { - CompletionCallback callback = user_callback_; - user_callback_.Reset(); - callback.Run(rv); + if (!wait_for_ready_callback_.is_null()) { + RecordLastFailure(); + base::ResetAndReturn(&wait_for_ready_callback_).Run(rv); } if (ready_ && !pending_write_data_.empty()) { DCHECK_EQ(NONE, state_); @@ -390,8 +395,19 @@ void DiskCacheBasedQuicServerInfo::RecordQuicServerInfoStatus( } } +void DiskCacheBasedQuicServerInfo::RecordLastFailure() { + if (last_failure_ != NO_FAILURE) { + UMA_HISTOGRAM_ENUMERATION( + "Net.QuicDiskCache.FailureReason.WaitForDataReady", + last_failure_, NUM_OF_FAILURES); + } + last_failure_ = NO_FAILURE; +} + void DiskCacheBasedQuicServerInfo::RecordQuicServerInfoFailure( FailureReason failure) { + last_failure_ = failure; + if (!backend_) { UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason.NoBackend", failure, NUM_OF_FAILURES); diff --git a/net/http/disk_cache_based_quic_server_info.h b/net/http/disk_cache_based_quic_server_info.h index 0da2e1d75a30e..e95d5355c97d2 100644 --- a/net/http/disk_cache_based_quic_server_info.h +++ b/net/http/disk_cache_based_quic_server_info.h @@ -85,7 +85,8 @@ class NET_EXPORT_PRIVATE DiskCacheBasedQuicServerInfo READY_TO_PERSIST_FAILURE = 7, PERSIST_NO_BACKEND_FAILURE = 8, WRITE_FAILURE = 9, - NUM_OF_FAILURES = 10, + NO_FAILURE = 10, + NUM_OF_FAILURES = 11, }; ~DiskCacheBasedQuicServerInfo() override; @@ -126,9 +127,13 @@ class NET_EXPORT_PRIVATE DiskCacheBasedQuicServerInfo void RecordQuicServerInfoStatus(QuicServerInfoAPICall call); // Tracks in a histogram the failure reasons to read/load/write of - // QuicServerInfo to and from disk cache. + // QuicServerInfo to and from disk cache. It also saves the |failure| in + // |last_failure_|. void RecordQuicServerInfoFailure(FailureReason failure); + // Tracks in a histogram if |last_failure_| is not NO_FAILURE. + void RecordLastFailure(); + CacheOperationDataShim* data_shim_; // Owned by |io_callback_|. CompletionCallback io_callback_; State state_; @@ -140,13 +145,16 @@ class NET_EXPORT_PRIVATE DiskCacheBasedQuicServerInfo HttpCache* const http_cache_; disk_cache::Backend* backend_; disk_cache::Entry* entry_; - CompletionCallback user_callback_; + CompletionCallback wait_for_ready_callback_; scoped_refptr read_buffer_; scoped_refptr write_buffer_; std::string data_; base::TimeTicks load_start_time_; + FailureReason last_failure_; base::WeakPtrFactory weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(DiskCacheBasedQuicServerInfo); }; } // namespace net diff --git a/net/http/http_response_info.cc b/net/http/http_response_info.cc index 2ec0fb5cf2b0d..9569b38b01a5b 100644 --- a/net/http/http_response_info.cc +++ b/net/http/http_response_info.cc @@ -396,9 +396,9 @@ std::string HttpResponseInfo::ConnectionInfoToString( case CONNECTION_INFO_SPDY3: return "spdy/3"; case CONNECTION_INFO_SPDY4: - // This is the HTTP/2 draft-15 identifier. For internal + // This is the HTTP/2 draft 14 identifier. For internal // consistency, HTTP/2 is named SPDY4 within Chromium. - return "h2-15"; + return "h2-14"; case CONNECTION_INFO_QUIC1_SPDY3: return "quic/1+spdy/3"; case NUM_OF_CONNECTION_INFOS: diff --git a/net/http/http_server_properties.cc b/net/http/http_server_properties.cc index cc41ea86ad182..4433b4e1435b8 100644 --- a/net/http/http_server_properties.cc +++ b/net/http/http_server_properties.cc @@ -20,7 +20,7 @@ const char* const kAlternateProtocolStrings[] = { "npn-spdy/2", "npn-spdy/3", "npn-spdy/3.1", - "npn-h2-15", // HTTP/2 draft-15. Called SPDY4 internally. + "npn-h2-14", // HTTP/2 draft 14. Called SPDY4 internally. "quic" }; diff --git a/net/proxy/proxy_config_service_android.cc b/net/proxy/proxy_config_service_android.cc index f1a0b6cca54f7..50407fe21b7b4 100644 --- a/net/proxy/proxy_config_service_android.cc +++ b/net/proxy/proxy_config_service_android.cc @@ -197,7 +197,8 @@ class ProxyConfigServiceAndroid::Delegate : jni_delegate_(this), network_task_runner_(network_task_runner), jni_task_runner_(jni_task_runner), - get_property_callback_(get_property_callback) { + get_property_callback_(get_property_callback), + exclude_pac_url_(false) { } void SetupJNI() { @@ -271,13 +272,22 @@ class ProxyConfigServiceAndroid::Delegate const std::vector& exclusion_list) { DCHECK(OnJNIThread()); ProxyConfig proxy_config; - CreateStaticProxyConfig(host, port, pac_url, exclusion_list, &proxy_config); + if (exclude_pac_url_) { + CreateStaticProxyConfig(host, port, "", exclusion_list, &proxy_config); + } else { + CreateStaticProxyConfig(host, port, pac_url, exclusion_list, + &proxy_config); + } network_task_runner_->PostTask( FROM_HERE, base::Bind( &Delegate::SetNewConfigOnNetworkThread, this, proxy_config)); } + void set_exclude_pac_url(bool enabled) { + exclude_pac_url_ = enabled; + } + private: friend class base::RefCountedThreadSafe; @@ -344,6 +354,7 @@ class ProxyConfigServiceAndroid::Delegate scoped_refptr jni_task_runner_; GetPropertyCallback get_property_callback_; ProxyConfig proxy_config_; + bool exclude_pac_url_; DISALLOW_COPY_AND_ASSIGN(Delegate); }; @@ -366,6 +377,10 @@ bool ProxyConfigServiceAndroid::Register(JNIEnv* env) { return RegisterNativesImpl(env); } +void ProxyConfigServiceAndroid::set_exclude_pac_url(bool enabled) { + delegate_->set_exclude_pac_url(enabled); +} + void ProxyConfigServiceAndroid::AddObserver(Observer* observer) { delegate_->AddObserver(observer); } diff --git a/net/proxy/proxy_config_service_android.h b/net/proxy/proxy_config_service_android.h index d642d37c73e4f..cb15bc51f66c6 100644 --- a/net/proxy/proxy_config_service_android.h +++ b/net/proxy/proxy_config_service_android.h @@ -64,6 +64,11 @@ class NET_EXPORT ProxyConfigServiceAndroid : public ProxyConfigService { // Register JNI bindings. static bool Register(JNIEnv* env); + // Android provides a local HTTP proxy that does PAC resolution. When this + // setting is enabled, the proxy config service ignores the PAC URL and uses + // the local proxy for all proxy resolution. + void set_exclude_pac_url(bool enabled); + // ProxyConfigService: // Called only on the network thread. virtual void AddObserver(Observer* observer) override; diff --git a/net/quic/crypto/quic_crypto_client_config.cc b/net/quic/crypto/quic_crypto_client_config.cc index 5b120c9661a3c..4828c3afa236a 100644 --- a/net/quic/crypto/quic_crypto_client_config.cc +++ b/net/quic/crypto/quic_crypto_client_config.cc @@ -32,25 +32,21 @@ namespace net { namespace { -enum ServerConfigState { - // WARNING: Do not change the numerical values of any of server config state. - // Do not remove deprecated server config states - just comment them as - // deprecated. - SERVER_CONFIG_EMPTY = 0, - SERVER_CONFIG_INVALID = 1, - SERVER_CONFIG_CORRUPTED = 2, - SERVER_CONFIG_EXPIRED = 3, - SERVER_CONFIG_INVALID_EXPIRY = 4, - - // NOTE: Add new server config states only immediately above this line. Make - // sure to update the QuicServerConfigState enum in - // tools/metrics/histograms/histograms.xml accordingly. - SERVER_CONFIG_COUNT -}; - -void RecordServerConfigState(ServerConfigState server_config_state) { - UMA_HISTOGRAM_ENUMERATION("Net.QuicClientHelloServerConfigState", - server_config_state, SERVER_CONFIG_COUNT); +// Tracks the reason (the state of the server config) for sending inchoate +// ClientHello to the server. +void RecordInchoateClientHelloReason( + QuicCryptoClientConfig::CachedState::ServerConfigState state) { + UMA_HISTOGRAM_ENUMERATION( + "Net.QuicInchoateClientHelloReason", state, + QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT); +} + +// Tracks the state of the QUIC server information loaded from the disk cache. +void RecordDiskCacheServerConfigState( + QuicCryptoClientConfig::CachedState::ServerConfigState state) { + UMA_HISTOGRAM_ENUMERATION( + "Net.QuicServerInfo.DiskCacheState", state, + QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT); } } // namespace @@ -72,12 +68,12 @@ QuicCryptoClientConfig::CachedState::~CachedState() {} bool QuicCryptoClientConfig::CachedState::IsComplete(QuicWallTime now) const { if (server_config_.empty()) { - RecordServerConfigState(SERVER_CONFIG_EMPTY); + RecordInchoateClientHelloReason(SERVER_CONFIG_EMPTY); return false; } if (!server_config_valid_) { - RecordServerConfigState(SERVER_CONFIG_INVALID); + RecordInchoateClientHelloReason(SERVER_CONFIG_INVALID); return false; } @@ -85,13 +81,13 @@ bool QuicCryptoClientConfig::CachedState::IsComplete(QuicWallTime now) const { if (!scfg) { // Should be impossible short of cache corruption. DCHECK(false); - RecordServerConfigState(SERVER_CONFIG_CORRUPTED); + RecordInchoateClientHelloReason(SERVER_CONFIG_CORRUPTED); return false; } uint64 expiry_seconds; if (scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) { - RecordServerConfigState(SERVER_CONFIG_INVALID_EXPIRY); + RecordInchoateClientHelloReason(SERVER_CONFIG_INVALID_EXPIRY); return false; } if (now.ToUNIXSeconds() >= expiry_seconds) { @@ -99,7 +95,7 @@ bool QuicCryptoClientConfig::CachedState::IsComplete(QuicWallTime now) const { "Net.QuicClientHelloServerConfig.InvalidDuration", base::TimeDelta::FromSeconds(now.ToUNIXSeconds() - expiry_seconds), base::TimeDelta::FromMinutes(1), base::TimeDelta::FromDays(20), 50); - RecordServerConfigState(SERVER_CONFIG_EXPIRED); + RecordInchoateClientHelloReason(SERVER_CONFIG_EXPIRED); return false; } @@ -123,7 +119,8 @@ QuicCryptoClientConfig::CachedState::GetServerConfig() const { return scfg_.get(); } -QuicErrorCode QuicCryptoClientConfig::CachedState::SetServerConfig( +QuicCryptoClientConfig::CachedState::ServerConfigState +QuicCryptoClientConfig::CachedState::SetServerConfig( StringPiece server_config, QuicWallTime now, string* error_details) { const bool matches_existing = server_config == server_config_; @@ -141,18 +138,18 @@ QuicErrorCode QuicCryptoClientConfig::CachedState::SetServerConfig( if (!new_scfg) { *error_details = "SCFG invalid"; - return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + return SERVER_CONFIG_INVALID; } uint64 expiry_seconds; if (new_scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) { *error_details = "SCFG missing EXPY"; - return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + return SERVER_CONFIG_INVALID_EXPIRY; } if (now.ToUNIXSeconds() >= expiry_seconds) { *error_details = "SCFG has expired"; - return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED; + return SERVER_CONFIG_EXPIRED; } if (!matches_existing) { @@ -160,7 +157,7 @@ QuicErrorCode QuicCryptoClientConfig::CachedState::SetServerConfig( SetProofInvalid(); scfg_.reset(new_scfg_storage.release()); } - return QUIC_NO_ERROR; + return SERVER_CONFIG_VALID; } void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() { @@ -228,13 +225,15 @@ bool QuicCryptoClientConfig::CachedState::Initialize( DCHECK(server_config_.empty()); if (server_config.empty()) { + RecordDiskCacheServerConfigState(SERVER_CONFIG_EMPTY); return false; } string error_details; - QuicErrorCode error = SetServerConfig(server_config, now, - &error_details); - if (error != QUIC_NO_ERROR) { + ServerConfigState state = SetServerConfig(server_config, now, + &error_details); + RecordDiskCacheServerConfigState(state); + if (state != SERVER_CONFIG_VALID) { DVLOG(1) << "SetServerConfig failed with " << error_details; return false; } @@ -594,9 +593,15 @@ QuicErrorCode QuicCryptoClientConfig::CacheNewServerConfig( return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; } - QuicErrorCode error = cached->SetServerConfig(scfg, now, error_details); - if (error != QUIC_NO_ERROR) { - return error; + CachedState::ServerConfigState state = cached->SetServerConfig( + scfg, now, error_details); + if (state == CachedState::SERVER_CONFIG_EXPIRED) { + return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED; + } + // TODO(rtenneti): Return more specific error code than returning + // QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER. + if (state != CachedState::SERVER_CONFIG_VALID) { + return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; } StringPiece token; diff --git a/net/quic/crypto/quic_crypto_client_config.h b/net/quic/crypto/quic_crypto_client_config.h index 584e4874ed298..4bfed1bcd2b5f 100644 --- a/net/quic/crypto/quic_crypto_client_config.h +++ b/net/quic/crypto/quic_crypto_client_config.h @@ -35,6 +35,24 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { // over several connections to the same server. class NET_EXPORT_PRIVATE CachedState { public: + // Enum to track if the server config is valid or not. If it is not valid, + // it specifies why it is invalid. + enum ServerConfigState { + // WARNING: Do not change the numerical values of any of server config + // state. Do not remove deprecated server config states - just comment + // them as deprecated. + SERVER_CONFIG_EMPTY = 0, + SERVER_CONFIG_INVALID = 1, + SERVER_CONFIG_CORRUPTED = 2, + SERVER_CONFIG_EXPIRED = 3, + SERVER_CONFIG_INVALID_EXPIRY = 4, + SERVER_CONFIG_VALID = 5, + // NOTE: Add new server config states only immediately above this line. + // Make sure to update the QuicServerConfigState enum in + // tools/metrics/histograms/histograms.xml accordingly. + SERVER_CONFIG_COUNT + }; + CachedState(); ~CachedState(); @@ -54,9 +72,9 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { // SetServerConfig checks that |server_config| parses correctly and stores // it in |server_config_|. |now| is used to judge whether |server_config| // has expired. - QuicErrorCode SetServerConfig(base::StringPiece server_config, - QuicWallTime now, - std::string* error_details); + ServerConfigState SetServerConfig(base::StringPiece server_config, + QuicWallTime now, + std::string* error_details); // InvalidateServerConfig clears the cached server config (if any). void InvalidateServerConfig(); diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h index afd5ed4c6f7d3..ad920d0f21028 100644 --- a/net/quic/quic_protocol.h +++ b/net/quic/quic_protocol.h @@ -76,6 +76,9 @@ const QuicByteCount kDefaultSocketReceiveBuffer = 256 * 1024; // Smaller values are ignored. const QuicByteCount kMinSocketReceiveBuffer = 16 * 1024; +// Don't allow a client to suggest an RTT shorter than 10ms. +const uint32 kMinInitialRoundTripTimeUs = 10 * kNumMicrosPerMilli; + // Don't allow a client to suggest an RTT longer than 15 seconds. const uint32 kMaxInitialRoundTripTimeUs = 15 * kNumMicrosPerSecond; diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc index bdf86904e281e..9e2d04fb5af5c 100644 --- a/net/quic/quic_sent_packet_manager.cc +++ b/net/quic/quic_sent_packet_manager.cc @@ -97,12 +97,16 @@ QuicSentPacketManager::~QuicSentPacketManager() { void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) { if (config.HasReceivedInitialRoundTripTimeUs() && config.ReceivedInitialRoundTripTimeUs() > 0) { - rtt_stats_.set_initial_rtt_us(min(kMaxInitialRoundTripTimeUs, - config.ReceivedInitialRoundTripTimeUs())); - } else if (config.HasInitialRoundTripTimeUsToSend()) { rtt_stats_.set_initial_rtt_us( - min(kMaxInitialRoundTripTimeUs, - config.GetInitialRoundTripTimeUsToSend())); + max(kMinInitialRoundTripTimeUs, + min(kMaxInitialRoundTripTimeUs, + config.ReceivedInitialRoundTripTimeUs()))); + } else if (config.HasInitialRoundTripTimeUsToSend() && + config.GetInitialRoundTripTimeUsToSend() > 0) { + rtt_stats_.set_initial_rtt_us( + max(kMinInitialRoundTripTimeUs, + min(kMaxInitialRoundTripTimeUs, + config.GetInitialRoundTripTimeUsToSend()))); } // TODO(ianswett): BBR is currently a server only feature. if (FLAGS_quic_allow_bbr && diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc index 0ea6d7c16fbb4..076797af0a0bc 100644 --- a/net/quic/quic_stream_factory.cc +++ b/net/quic/quic_stream_factory.cc @@ -993,6 +993,8 @@ void QuicStreamFactory::ActivateSession( void QuicStreamFactory::InitializeCachedStateInCryptoConfig( const QuicServerId& server_id, const scoped_ptr& server_info) { + // |server_info| will be NULL, if a non-empty server config already exists in + // the memory cache. This is a minor optimization to avoid LookupOrCreate. if (!server_info) return; @@ -1001,6 +1003,27 @@ void QuicStreamFactory::InitializeCachedStateInCryptoConfig( if (!cached->IsEmpty()) return; + if (http_server_properties_) { + if (quic_supported_servers_at_startup_.empty()) { + for (const std::pair& + key_value : http_server_properties_->alternate_protocol_map()) { + if (key_value.second.protocol == QUIC) { + quic_supported_servers_at_startup_.insert(key_value.first); + } + } + } + + // TODO(rtenneti): Delete the following histogram after collecting stats. + // If the AlternateProtocolMap contained an entry for this host, check if + // the disk cache contained an entry for it. + if (ContainsKey(quic_supported_servers_at_startup_, + server_id.host_port_pair())) { + UMA_HISTOGRAM_BOOLEAN( + "Net.QuicServerInfo.ExpectConfigMissingFromDiskCache", + server_info->state().server_config.empty()); + } + } + if (!cached->Initialize(server_info->state().server_config, server_info->state().source_address_token, server_info->state().certs, diff --git a/net/quic/quic_stream_factory.h b/net/quic/quic_stream_factory.h index c892cb2b1d917..2fad1fc709fda 100644 --- a/net/quic/quic_stream_factory.h +++ b/net/quic/quic_stream_factory.h @@ -299,6 +299,7 @@ class NET_EXPORT_PRIVATE QuicStreamFactory // Local address of socket that was created in CreateSession. IPEndPoint local_address_; bool check_persisted_supports_quic_; + std::set quic_supported_servers_at_startup_; base::TaskRunner* task_runner_; diff --git a/net/quic/quic_time.h b/net/quic/quic_time.h index 5fbe30cce9890..53e5ebe02c20f 100644 --- a/net/quic/quic_time.h +++ b/net/quic/quic_time.h @@ -18,6 +18,8 @@ namespace net { static const uint64 kNumMicrosPerSecond = base::Time::kMicrosecondsPerSecond; +static const uint64 kNumMicrosPerMilli = + base::Time::kMicrosecondsPerMillisecond; // A QuicTime is a purely relative time. QuicTime values from different clocks // cannot be compared to each other. If you need an absolute time, see diff --git a/net/socket/next_proto.h b/net/socket/next_proto.h index 89400a9ee4d11..4df6e9b9cd5ea 100644 --- a/net/socket/next_proto.h +++ b/net/socket/next_proto.h @@ -27,8 +27,7 @@ enum NextProto { kProtoSPDYMinimumVersion = kProtoDeprecatedSPDY2, kProtoSPDY3 = 101, kProtoSPDY31 = 102, - // HTTP/2 draft-14 was 103, - kProtoSPDY4 = 104, // SPDY4 is HTTP/2 draft-15. + kProtoSPDY4 = 103, // SPDY4 is HTTP/2. kProtoSPDYMaximumVersion = kProtoSPDY4, kProtoQUIC1SPDY3 = 200, diff --git a/net/socket/ssl_client_socket.cc b/net/socket/ssl_client_socket.cc index 269ca7ee6f34b..3184e04e3f79b 100644 --- a/net/socket/ssl_client_socket.cc +++ b/net/socket/ssl_client_socket.cc @@ -37,8 +37,8 @@ NextProto SSLClientSocket::NextProtoFromString( return kProtoSPDY3; } else if (proto_string == "spdy/3.1") { return kProtoSPDY31; - } else if (proto_string == "h2-15") { - // This is the HTTP/2 draft-15 identifier. For internal + } else if (proto_string == "h2-14") { + // This is the HTTP/2 draft 14 identifier. For internal // consistency, HTTP/2 is named SPDY4 within Chromium. return kProtoSPDY4; } else if (proto_string == "quic/1+spdy/3") { @@ -60,9 +60,9 @@ const char* SSLClientSocket::NextProtoToString(NextProto next_proto) { case kProtoSPDY31: return "spdy/3.1"; case kProtoSPDY4: - // This is the HTTP/2 draft-15 identifier. For internal + // This is the HTTP/2 draft 14 identifier. For internal // consistency, HTTP/2 is named SPDY4 within Chromium. - return "h2-15"; + return "h2-14"; case kProtoQUIC1SPDY3: return "quic/1+spdy/3"; case kProtoUnknown: diff --git a/net/test/test_certificate_data.h b/net/test/test_certificate_data.h index 17de41f5f684e..3ccda5e34cb0f 100644 --- a/net/test/test_certificate_data.h +++ b/net/test/test_certificate_data.h @@ -9,26 +9,22 @@ static const char kNistSPKIHash[] = "\x15\x60\xde\x65\x4e\x03\x9f\xd0\x08\x82" "\xa9\x6a\xc4\x65\x8e\x6f\x92\x06\x84\x35"; -// kTwitterSPKIs contains the SHA1 hashes of the SPKIs of the twitter-chain.pem +// kSatvedaSPKIs contains the SHA1 hashes of the SPKIs of the satveda.pem // certificate chain, in order. -static const char kTwitterSPKIs[3][21] = { - "\x26\x9a\x19\xa3\x88\x28\xc1\xdd\x70\x1b" - "\xa0\xca\x2c\x98\xdb\xc6\xe1\x4f\x37\x3e", - "\x47\x49\xdf\x16\x57\xf4\x6c\x8b\xd2\x8c" - "\x79\x1b\x99\xfb\x9f\x28\x81\x2a\x60\xe0", - "\xb1\x81\x08\x1a\x19\xa4\xc0\x94\x1f\xfa" - "\xe8\x95\x28\xc1\x24\xc9\x9b\x34\xac\xc7", +static const char kSatvedaSPKIs[2][21] = { + "\xd6\x2d\x7a\x12\x02\x7f\x9b\x8e\x4f\x2b" + "\x07\xc5\xfb\xf9\x2a\x2e\x9a\xcc\x0e\xe3", + "\xba\x2e\xb5\xa8\x3e\x13\x23\xd9\x53\x4b" + "\x5e\x65\xbc\xe7\xa3\x13\x5d\xd0\xa9\x96", }; -// kTwitterSPKIsSHA256 contains the SHA256 hashes of the SPKIs of the -// twitter-chain.pem certificate chain, in order. -static const char kTwitterSPKIsSHA256[3][33] = { - "\x20\xec\x5d\x0a\xfb\xc6\xc0\xe2\xe1\x95\x56\xc5\x35\x2b\x3c\x60" - "\x78\xa6\xed\x95\x55\xc2\xfa\x86\x82\x40\x4f\xdb\x55\x29\xd3\xad", - "\x80\xcc\x56\x3a\xb5\xf8\x3c\xc4\x1e\xb0\xaf\x6a\x14\xd6\xd8\x07" - "\x18\xc1\x7e\x35\x2f\x96\x49\xff\xbc\xdd\x67\xf8\xbf\x65\x13\x91", - "\x25\xb4\x1b\x50\x6e\x49\x30\x95\x28\x23\xa6\xeb\x9f\x1d\x31\xde" - "\xf6\x45\xea\x38\xa5\xc6\xc6\xa9\x6d\x71\x95\x7e\x38\x4d\xf0\x58", +// kSatvedaSPKIsSHA256 contains the SHA256 hashes of the SPKIs of the +// satveda.pem certificate chain, in order. +static const char kSatvedaSPKIsSHA256[2][33] = { + "\xb9\x42\xab\xf2\x08\x63\xef\x81\x70\x88\x45\xc4\x39\xa2\x6e\x9c" + "\x2f\x9a\xf9\xf4\xcb\x23\x61\xd4\x83\x97\x61\x6d\xf2\x5b\x27\xa8", + "\x32\xb6\x4b\x66\x72\x7a\x20\x63\xe4\x06\x6f\x3b\x95\x8c\xb0\xaa" + "\xee\x57\x6a\x5e\xce\xfd\x95\x33\x99\xbb\x88\x74\x73\x1d\x95\x87", }; // Certificates for test data. They're obtained with: diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc index 55e2d88456508..1fb3e79aa9959 100644 --- a/net/tools/quic/end_to_end_test.cc +++ b/net/tools/quic/end_to_end_test.cc @@ -924,7 +924,7 @@ TEST_P(EndToEndTest, LimitCongestionWindowAndRTT) { // Client tries to request twice the server's max initial window, and the // server limits it to the max. client_config_.SetInitialCongestionWindowToSend(2 * kMaxInitialWindow); - client_config_.SetInitialRoundTripTimeUsToSend(1000); + client_config_.SetInitialRoundTripTimeUsToSend(20000); ASSERT_TRUE(Initialize()); client_->client()->WaitForCryptoHandshakeConfirmed(); @@ -949,9 +949,9 @@ TEST_P(EndToEndTest, LimitCongestionWindowAndRTT) { EXPECT_EQ(GetParam().use_pacing, server_sent_packet_manager.using_pacing()); EXPECT_EQ(GetParam().use_pacing, client_sent_packet_manager.using_pacing()); - // The client *should* set the intitial RTT. - EXPECT_EQ(1000u, client_sent_packet_manager.GetRttStats()->initial_rtt_us()); - EXPECT_EQ(1000u, server_sent_packet_manager.GetRttStats()->initial_rtt_us()); + // The client *should* set the intitial RTT, but it's increased to 10ms. + EXPECT_EQ(20000u, client_sent_packet_manager.GetRttStats()->initial_rtt_us()); + EXPECT_EQ(20000u, server_sent_packet_manager.GetRttStats()->initial_rtt_us()); // Now use the negotiated limits with packet loss. SetPacketLossPercentage(30); diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc index 666bd03653a8a..c3b1cad1abb6a 100644 --- a/net/url_request/url_request_context_builder.cc +++ b/net/url_request/url_request_context_builder.cc @@ -214,7 +214,8 @@ URLRequestContextBuilder::URLRequestContextBuilder() ftp_enabled_(false), #endif http_cache_enabled_(true), - throttling_enabled_(false) { + throttling_enabled_(false), + channel_id_enabled_(true) { } URLRequestContextBuilder::~URLRequestContextBuilder() {} @@ -296,12 +297,14 @@ URLRequestContext* URLRequestContextBuilder::Build() { storage->set_http_auth_handler_factory(http_auth_handler_registry_factory); storage->set_cookie_store(new CookieMonster(NULL, NULL)); - // TODO(mmenke): This always creates a file thread, even when it ends up - // not being used. Consider lazily creating the thread. - storage->set_channel_id_service( - new ChannelIDService( - new DefaultChannelIDStore(NULL), - context->GetFileThread()->message_loop_proxy())); + if (channel_id_enabled_) { + // TODO(mmenke): This always creates a file thread, even when it ends up + // not being used. Consider lazily creating the thread. + storage->set_channel_id_service( + new ChannelIDService( + new DefaultChannelIDStore(NULL), + context->GetFileThread()->message_loop_proxy())); + } storage->set_transport_security_state(new net::TransportSecurityState()); if (!transport_security_persister_path_.empty()) { diff --git a/net/url_request/url_request_context_builder.h b/net/url_request/url_request_context_builder.h index 90533727097a8..233918cdf1d8a 100644 --- a/net/url_request/url_request_context_builder.h +++ b/net/url_request/url_request_context_builder.h @@ -166,6 +166,10 @@ class NET_EXPORT URLRequestContextBuilder { throttling_enabled_ = throttling_enabled; } + void set_channel_id_enabled(bool enable) { + channel_id_enabled_ = enable; + } + URLRequestContext* Build(); private: @@ -192,6 +196,7 @@ class NET_EXPORT URLRequestContextBuilder { #endif bool http_cache_enabled_; bool throttling_enabled_; + bool channel_id_enabled_; HttpCacheParams http_cache_params_; HttpNetworkSessionParams http_network_session_params_; diff --git a/net/url_request/url_request_job_manager.h b/net/url_request/url_request_job_manager.h index 9877bed1891a2..4fe6376c607a9 100644 --- a/net/url_request/url_request_job_manager.h +++ b/net/url_request/url_request_job_manager.h @@ -10,6 +10,7 @@ #include "base/synchronization/lock.h" #include "base/threading/platform_thread.h" +#include "net/base/net_export.h" #include "net/url_request/url_request.h" template struct DefaultSingletonTraits; @@ -24,7 +25,7 @@ namespace net { // URLRequest is designed to have all consumers on a single thread, and // so no attempt is made to support Interceptor instances being // registered/unregistered or in any way poked on multiple threads. -class URLRequestJobManager { +class NET_EXPORT URLRequestJobManager { public: // Returns the singleton instance. static URLRequestJobManager* GetInstance(); diff --git a/ppapi/proxy/host_dispatcher.cc b/ppapi/proxy/host_dispatcher.cc index 0e821db81dd64..ee7e91905b111 100644 --- a/ppapi/proxy/host_dispatcher.cc +++ b/ppapi/proxy/host_dispatcher.cc @@ -224,7 +224,10 @@ const void* HostDispatcher::GetProxiedInterface(const std::string& iface_name) { // Need to query. Cache the result so we only do this once. bool supported = false; - Send(new PpapiMsg_IsInterfaceSupported(iface_name, &supported)); + bool previous_reentrancy_value = allow_plugin_reentrancy_; + allow_plugin_reentrancy_ = true; + Send(new PpapiMsg_SupportsInterface(iface_name, &supported)); + allow_plugin_reentrancy_ = previous_reentrancy_value; std::pair iter_success_pair; iter_success_pair = plugin_supported_.insert( @@ -271,11 +274,6 @@ void HostDispatcher::OnHostMsgLogWithSource(PP_Instance instance, } } -void HostDispatcher::OnHostMsgPluginSupportsInterface( - const std::string& interface_name) { - plugin_supported_[interface_name] = true; -} - // ScopedModuleReference ------------------------------------------------------- ScopedModuleReference::ScopedModuleReference(Dispatcher* dispatcher) diff --git a/ppapi/proxy/host_dispatcher.h b/ppapi/proxy/host_dispatcher.h index 0f503ffa5a4db..345f8eab6872f 100644 --- a/ppapi/proxy/host_dispatcher.h +++ b/ppapi/proxy/host_dispatcher.h @@ -122,7 +122,6 @@ class PPAPI_PROXY_EXPORT HostDispatcher : public Dispatcher { int int_log_level, const std::string& source, const std::string& value); - void OnHostMsgPluginSupportsInterface(const std::string& interface_name); void RemoveSyncMessageStatusObserver(SyncMessageStatusObserver* obs); diff --git a/ppapi/proxy/plugin_dispatcher.cc b/ppapi/proxy/plugin_dispatcher.cc index c3e96e28ce98a..ad3e7a066429e 100644 --- a/ppapi/proxy/plugin_dispatcher.cc +++ b/ppapi/proxy/plugin_dispatcher.cc @@ -223,8 +223,7 @@ bool PluginDispatcher::OnMessageReceived(const IPC::Message& msg) { // Handle some plugin-specific control messages. bool handled = true; IPC_BEGIN_MESSAGE_MAP(PluginDispatcher, msg) - IPC_MESSAGE_HANDLER(PpapiMsg_IsInterfaceSupported, - OnMsgIsInterfaceSupported) + IPC_MESSAGE_HANDLER(PpapiMsg_SupportsInterface, OnMsgSupportsInterface) IPC_MESSAGE_HANDLER(PpapiMsg_SetPreferences, OnMsgSetPreferences) IPC_MESSAGE_UNHANDLED(handled = false); IPC_END_MESSAGE_MAP() @@ -298,7 +297,7 @@ void PluginDispatcher::ForceFreeAllInstances() { } } -void PluginDispatcher::OnMsgIsInterfaceSupported( +void PluginDispatcher::OnMsgSupportsInterface( const std::string& interface_name, bool* result) { *result = !!GetPluginInterface(interface_name); diff --git a/ppapi/proxy/plugin_dispatcher.h b/ppapi/proxy/plugin_dispatcher.h index 2dc526f4cdfe0..f8e22f6ebdedb 100644 --- a/ppapi/proxy/plugin_dispatcher.h +++ b/ppapi/proxy/plugin_dispatcher.h @@ -175,8 +175,7 @@ class PPAPI_PROXY_EXPORT PluginDispatcher void ForceFreeAllInstances(); // IPC message handlers. - void OnMsgIsInterfaceSupported( - const std::string& interface_name, bool* result); + void OnMsgSupportsInterface(const std::string& interface_name, bool* result); void OnMsgSetPreferences(const Preferences& prefs); virtual bool SendMessage(IPC::Message* msg); diff --git a/ppapi/proxy/plugin_dispatcher_unittest.cc b/ppapi/proxy/plugin_dispatcher_unittest.cc index 83a5cf4687dcc..821ecad3799c3 100644 --- a/ppapi/proxy/plugin_dispatcher_unittest.cc +++ b/ppapi/proxy/plugin_dispatcher_unittest.cc @@ -62,10 +62,10 @@ TEST_F(PluginDispatcherTest, SupportsInterface) { RegisterTestInterface(PPP_INSTANCE_INTERFACE, &dummy_ppp_instance_interface); // Sending a request for a random interface should fail. - EXPECT_FALSE(IsInterfaceSupported("Random interface")); + EXPECT_FALSE(SupportsInterface("Random interface")); // Sending a request for a supported PPP interface should succeed. - EXPECT_TRUE(IsInterfaceSupported(PPP_INSTANCE_INTERFACE)); + EXPECT_TRUE(SupportsInterface(PPP_INSTANCE_INTERFACE)); } TEST_F(PluginDispatcherTest, PPBCreation) { diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h index 135786cd220cd..484e6c74a2d35 100644 --- a/ppapi/proxy/ppapi_messages.h +++ b/ppapi/proxy/ppapi_messages.h @@ -486,13 +486,9 @@ IPC_MESSAGE_CONTROL1(PpapiMsg_SetPreferences, // Sent in both directions to see if the other side supports the given // interface. -IPC_SYNC_MESSAGE_CONTROL1_1(PpapiMsg_IsInterfaceSupported, +IPC_SYNC_MESSAGE_CONTROL1_1(PpapiMsg_SupportsInterface, std::string /* interface_name */, bool /* result */) -// Sent by the plugin side of the proxy to inform the renderer that a given -// plugin interface (PPP_*) is supported. -IPC_MESSAGE_CONTROL1(PpapiHostMsg_PluginSupportsInterface, - std::string /* interface_name */) IPC_MESSAGE_CONTROL1(PpapiHostMsg_LogInterfaceUsage, int /* interface_hash */) @@ -1184,9 +1180,9 @@ IPC_SYNC_MESSAGE_ROUTED3_1( IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBTesting_GetLiveObjectsForInstance, PP_Instance /* instance */, uint32 /* result */) -IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBTesting_SimulateInputEvent, - PP_Instance /* instance */, - ppapi::InputEventData /* input_event */) +IPC_SYNC_MESSAGE_ROUTED2_0(PpapiHostMsg_PPBTesting_SimulateInputEvent, + PP_Instance /* instance */, + ppapi::InputEventData /* input_event */) IPC_SYNC_MESSAGE_ROUTED1_0( PpapiHostMsg_PPBTesting_SetMinimumArrayBufferSizeForShmem, uint32_t /* threshold */) diff --git a/ppapi/proxy/ppapi_proxy_test.cc b/ppapi/proxy/ppapi_proxy_test.cc index b75f4b83b19bd..2c0b1365d3584 100644 --- a/ppapi/proxy/ppapi_proxy_test.cc +++ b/ppapi/proxy/ppapi_proxy_test.cc @@ -122,13 +122,13 @@ void ProxyTestHarnessBase::RegisterTestInterface(const char* name, registered_interfaces_[name] = test_interface; } -bool ProxyTestHarnessBase::IsInterfaceSupported(const char* name) { +bool ProxyTestHarnessBase::SupportsInterface(const char* name) { sink().ClearMessages(); // IPC doesn't actually write to this when we send a message manually // not actually using IPC. bool unused_result = false; - PpapiMsg_IsInterfaceSupported msg(name, &unused_result); + PpapiMsg_SupportsInterface msg(name, &unused_result); GetDispatcher()->OnMessageReceived(msg); const IPC::Message* reply_msg = @@ -137,8 +137,8 @@ bool ProxyTestHarnessBase::IsInterfaceSupported(const char* name) { if (!reply_msg) return false; - TupleTypes::ValueTuple reply_data; - EXPECT_TRUE(PpapiMsg_IsInterfaceSupported::ReadReplyParam( + TupleTypes::ValueTuple reply_data; + EXPECT_TRUE(PpapiMsg_SupportsInterface::ReadReplyParam( reply_msg, &reply_data)); sink().ClearMessages(); diff --git a/ppapi/proxy/ppapi_proxy_test.h b/ppapi/proxy/ppapi_proxy_test.h index c0c11cd6389ca..ce9ec655f72d3 100644 --- a/ppapi/proxy/ppapi_proxy_test.h +++ b/ppapi/proxy/ppapi_proxy_test.h @@ -76,7 +76,7 @@ class ProxyTestHarnessBase { // Sends a "supports interface" message to the current dispatcher and returns // true if it's supported. This is just for the convenience of tests. - bool IsInterfaceSupported(const char* name); + bool SupportsInterface(const char* name); private: // Destination for IPC messages sent by the test. diff --git a/ppapi/proxy/ppb_video_decoder_proxy.cc b/ppapi/proxy/ppb_video_decoder_proxy.cc index 8913c01624b37..7699c84ecaab1 100644 --- a/ppapi/proxy/ppb_video_decoder_proxy.cc +++ b/ppapi/proxy/ppb_video_decoder_proxy.cc @@ -6,7 +6,6 @@ #include "base/logging.h" #include "gpu/command_buffer/client/gles2_implementation.h" -#include "ppapi/c/dev/ppp_video_decoder_dev.h" #include "ppapi/proxy/enter_proxy.h" #include "ppapi/proxy/plugin_dispatcher.h" #include "ppapi/proxy/ppapi_messages.h" @@ -196,14 +195,6 @@ PP_Resource PPB_VideoDecoder_Proxy::CreateProxyResource( if (!dispatcher->preferences().is_accelerated_video_decode_enabled) return 0; - // We must get the plugin interface now, prior to doing Create synchronously. - // Otherwise, the browser will try to get the interface via a re-entrant - // sync message back to us, which would deadlock. - const std::string if_name = PPP_VIDEODECODER_DEV_INTERFACE_0_11; - if (!dispatcher->GetPluginInterface(if_name)) - return 0; - dispatcher->Send(new PpapiHostMsg_PluginSupportsInterface(if_name)); - EnterResourceNoLock enter_context(graphics_context, true); if (enter_context.failed()) diff --git a/remoting/codec/video_encoder_vpx.cc b/remoting/codec/video_encoder_vpx.cc index 3ee9e6ac57e42..d45da404ad88a 100644 --- a/remoting/codec/video_encoder_vpx.cc +++ b/remoting/codec/video_encoder_vpx.cc @@ -56,6 +56,9 @@ void SetCommonCodecParameters(const webrtc::DesktopSize& size, // Start emitting packets immediately. config->g_lag_in_frames = 0; + // Since the transport layer is reliable, keyframes aren't necessary. + config->kf_mode = VPX_KF_DISABLED; + // Using 2 threads gives a great boost in performance for most systems with // adequate processing power. NB: Going to multiple threads on low end // windows systems can really hurt performance. diff --git a/remoting/host/installer/linux/debian/postinst b/remoting/host/installer/linux/debian/postinst index 10d6fc55e41e6..b7adfc4d6a9bc 100755 --- a/remoting/host/installer/linux/debian/postinst +++ b/remoting/host/installer/linux/debian/postinst @@ -22,8 +22,10 @@ HASHES_FILE="$VAR_DIR/hashes" case "$1" in "configure") # Kill host processes. The wrapper script will restart them. + # TODO(lambroslambrou): Remove the '-9' when the underlying problem with + # hosts not responding to SIGTERM has been fixed - http://crbug.com/420090 echo "Shutting down Chrome Remote Desktop hosts (they will restart automatically)..." - killall -q chrome-remote-desktop-host || true + killall -9 -q chrome-remote-desktop-host || true # If any files have changed that require the user to restart their virtual # desktops (eg, the wrapper script itself) then notify them but don't do # anything that would result in them losing state. diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc index f880803c2c338..40bc6fb36532e 100644 --- a/remoting/host/remoting_me2me_host.cc +++ b/remoting/host/remoting_me2me_host.cc @@ -936,20 +936,21 @@ void HostProcess::OnPolicyUpdate(scoped_ptr policies) { void HostProcess::ApplyHostDomainPolicy() { HOST_LOG << "Policy sets host domain: " << host_domain_; - // If the user does not have a Google email, their client JID will not be - // based on their email. In that case, the username/host domain policies would - // be meaningless, since there is no way to check that the JID attempting to - // connect actually corresponds to the owner email in question. - if (host_owner_ != host_owner_email_) { - LOG(ERROR) << "The username and host domain policies cannot be enabled for " - << "accounts with a non-Google email."; - ShutdownHost(kInvalidHostDomainExitCode); - } + if (!host_domain_.empty()) { + // If the user does not have a Google email, their client JID will not be + // based on their email. In that case, the username/host domain policies + // would be meaningless, since there is no way to check that the JID + // trying to connect actually corresponds to the owner email in question. + if (host_owner_ != host_owner_email_) { + LOG(ERROR) << "The username and host domain policies cannot be enabled " + << "for accounts with a non-Google email."; + ShutdownHost(kInvalidHostDomainExitCode); + } - if (!host_domain_.empty() && - !EndsWith(host_owner_, std::string("@") + host_domain_, false)) { - LOG(ERROR) << "The host domain does not match the policy."; - ShutdownHost(kInvalidHostDomainExitCode); + if (!EndsWith(host_owner_, std::string("@") + host_domain_, false)) { + LOG(ERROR) << "The host domain does not match the policy."; + ShutdownHost(kInvalidHostDomainExitCode); + } } } @@ -967,15 +968,16 @@ bool HostProcess::OnHostDomainPolicyUpdate(base::DictionaryValue* policies) { } void HostProcess::ApplyUsernamePolicy() { - // See comment in ApplyHostDomainPolicy. - if (host_owner_ != host_owner_email_) { - LOG(ERROR) << "The username and host domain policies cannot be enabled for " - << "accounts with a non-Google email."; - ShutdownHost(kUsernameMismatchExitCode); - } - if (host_username_match_required_) { HOST_LOG << "Policy requires host username match."; + + // See comment in ApplyHostDomainPolicy. + if (host_owner_ != host_owner_email_) { + LOG(ERROR) << "The username and host domain policies cannot be enabled " + << "for accounts with a non-Google email."; + ShutdownHost(kUsernameMismatchExitCode); + } + std::string username = GetUsername(); bool shutdown = username.empty() || !StartsWithASCII(host_owner_, username + std::string("@"), diff --git a/remoting/webapp/base/html/main.css b/remoting/webapp/base/html/main.css index d1ffd11208377..8d7a52c3f8107 100644 --- a/remoting/webapp/base/html/main.css +++ b/remoting/webapp/base/html/main.css @@ -673,11 +673,9 @@ html.apps-v2.scrollable { #session-client-plugin { box-shadow: 0 0 8px 0 black; -webkit-user-select: none; -} - -#session-client-plugin { display: block; flex-shrink: 0; + z-index: 2; /* Show above the dialog screen so that click-to-play works. */ } .session-client-inactive { diff --git a/remoting/webapp/crd/js/client_session.js b/remoting/webapp/crd/js/client_session.js index 456f8adeaf466..cbe22d42a3dee 100644 --- a/remoting/webapp/crd/js/client_session.js +++ b/remoting/webapp/crd/js/client_session.js @@ -993,6 +993,16 @@ remoting.ClientSession.prototype.onRouteChanged_ = * @param {boolean} ready True if the connection is ready. */ remoting.ClientSession.prototype.onConnectionReady_ = function(ready) { + // TODO(jamiewalch): Currently, the logic for determining whether or not the + // connection is available is based solely on whether or not any video frames + // have been received recently. which leads to poor UX on slow connections. + // Re-enable this once crbug.com/435315 has been fixed. + var ignoreVideoChannelState = true; + if (ignoreVideoChannelState) { + console.log('Video channel ' + (ready ? '' : 'not ') + 'ready.'); + return; + } + if (!ready) { this.container_.classList.add('session-client-inactive'); } else { diff --git a/remoting/webapp/crd/js/host_controller.js b/remoting/webapp/crd/js/host_controller.js index 7473c8c2ae33c..45ef3660556d7 100644 --- a/remoting/webapp/crd/js/host_controller.js +++ b/remoting/webapp/crd/js/host_controller.js @@ -253,7 +253,8 @@ remoting.HostController.prototype.start = function(hostPin, consent, onDone, newHostId, hostPin, startHostWithHash.bind( null, hostName, publicKey, privateKey, remoting.identity.getCachedEmail(), - remoting.oauth2.getRefreshToken()), + remoting.oauth2.getRefreshToken(), + remoting.identity.getCachedEmail()), onError); } } else { diff --git a/third_party/libaddressinput/BUILD.gn b/third_party/libaddressinput/BUILD.gn index bb32d46fd20e5..6f5d9037f1ff5 100644 --- a/third_party/libaddressinput/BUILD.gn +++ b/third_party/libaddressinput/BUILD.gn @@ -128,6 +128,57 @@ static_library("util") { if (is_android) { import("//build/config/android/rules.gni") + # GYP: //third_party/libaddressinput/libaddressinput.gyp:libaddressinput_android_strings_grd + java_strings_grd("libaddressinput_android_strings_grd") { + grd_file = "//chrome/app/address_input_strings_android.grd" + outputs = [ + "values-am/address_input_strings.xml", + "values-ar/address_input_strings.xml", + "values-bg/address_input_strings.xml", + "values-ca/address_input_strings.xml", + "values-cs/address_input_strings.xml", + "values-da/address_input_strings.xml", + "values-de/address_input_strings.xml", + "values-el/address_input_strings.xml", + "values-en-rGB/address_input_strings.xml", + "values-es-rUS/address_input_strings.xml", + "values-es/address_input_strings.xml", + "values-fa/address_input_strings.xml", + "values-fi/address_input_strings.xml", + "values-fr/address_input_strings.xml", + "values-hi/address_input_strings.xml", + "values-hr/address_input_strings.xml", + "values-hu/address_input_strings.xml", + "values-in/address_input_strings.xml", + "values-it/address_input_strings.xml", + "values-iw/address_input_strings.xml", + "values-ja/address_input_strings.xml", + "values-ko/address_input_strings.xml", + "values-lt/address_input_strings.xml", + "values-lv/address_input_strings.xml", + "values-nb/address_input_strings.xml", + "values-nl/address_input_strings.xml", + "values-pl/address_input_strings.xml", + "values-pt-rBR/address_input_strings.xml", + "values-pt-rPT/address_input_strings.xml", + "values-ro/address_input_strings.xml", + "values-ru/address_input_strings.xml", + "values-sk/address_input_strings.xml", + "values-sl/address_input_strings.xml", + "values-sr/address_input_strings.xml", + "values-sv/address_input_strings.xml", + "values-sw/address_input_strings.xml", + "values-th/address_input_strings.xml", + "values-tl/address_input_strings.xml", + "values-tr/address_input_strings.xml", + "values-uk/address_input_strings.xml", + "values-vi/address_input_strings.xml", + "values-zh-rCN/address_input_strings.xml", + "values-zh-rTW/address_input_strings.xml", + "values/address_input_strings.xml", + ] + } + android_resources("android_addressinput_widget_resources") { custom_package = "com.android.i18n.addressinput" resource_dirs = [ "src/java/res" ] @@ -137,7 +188,10 @@ if (is_android) { # GYP: //third_party/libaddressinput/libaddressinput.gyp:android_addressinput_widget android_library("android_addressinput_widget_java") { DEPRECATED_java_in_dir = "src/java/src" - deps = [ ":android_addressinput_widget_resources" ] + deps = [ + ":android_addressinput_widget_resources", + ":libaddressinput_android_strings_grd", + ] } } else { # The list of files in libaddressinput.gypi. diff --git a/third_party/libaddressinput/libaddressinput.gyp b/third_party/libaddressinput/libaddressinput.gyp index db2b466b944ff..2ea754b529ad3 100644 --- a/third_party/libaddressinput/libaddressinput.gyp +++ b/third_party/libaddressinput/libaddressinput.gyp @@ -164,6 +164,18 @@ 'conditions': [ ['OS=="android"', { 'targets': [ + { + # GN: //third_party/libaddressinput:libaddressinput_android_strings_grd + 'target_name': 'libaddressinput_android_strings_grd', + 'type': 'none', + 'android_unmangled_name': 1, + 'variables': { + 'grd_file': '../../chrome/app/address_input_strings_android.grd', + }, + 'includes': [ + '../../build/java_strings_grd.gypi', + ], + }, { # GN: //third_party/libaddressinput:android_addressinput_widget_java 'target_name': 'android_addressinput_widget', @@ -179,6 +191,9 @@ 'includes': [ '../../build/java.gypi', ], + 'dependencies': [ + 'libaddressinput_android_strings_grd', + ], }, ], },], diff --git a/third_party/libjingle/BUILD.gn b/third_party/libjingle/BUILD.gn index 38f0a020a368a..f56e81ea6f2fa 100644 --- a/third_party/libjingle/BUILD.gn +++ b/third_party/libjingle/BUILD.gn @@ -552,7 +552,6 @@ if (enable_webrtc) { deps = [ ":libjingle_webrtc_common", "//third_party/webrtc", - "//third_party/webrtc/modules/audio_processing", "//third_party/webrtc/system_wrappers", "//third_party/webrtc/voice_engine", ] diff --git a/third_party/libjingle/libjingle.gyp b/third_party/libjingle/libjingle.gyp index cc48f249dac2c..f0628419c7918 100644 --- a/third_party/libjingle/libjingle.gyp +++ b/third_party/libjingle/libjingle.gyp @@ -598,7 +598,6 @@ '<(libjingle_source)/talk/media/webrtc/webrtcvoiceengine.h', ], 'dependencies': [ - '<(DEPTH)/third_party/webrtc/modules/modules.gyp:audio_processing', '<(DEPTH)/third_party/webrtc/system_wrappers/source/system_wrappers.gyp:system_wrappers', '<(DEPTH)/third_party/webrtc/voice_engine/voice_engine.gyp:voice_engine', '<(DEPTH)/third_party/webrtc/webrtc.gyp:webrtc', diff --git a/third_party/libjingle/overrides/init_webrtc.cc b/third_party/libjingle/overrides/init_webrtc.cc index b160cbb1bf1ed..041fb20b05c1c 100644 --- a/third_party/libjingle/overrides/init_webrtc.cc +++ b/third_party/libjingle/overrides/init_webrtc.cc @@ -12,8 +12,6 @@ #include "base/metrics/histogram.h" #include "base/native_library.h" #include "base/path_service.h" -#include "third_party/webrtc/common.h" -#include "third_party/webrtc/modules/audio_processing/include/audio_processing.h" #include "webrtc/base/basictypes.h" #include "webrtc/base/logging.h" @@ -82,13 +80,6 @@ bool InitializeWebRtcModule() { return true; } -webrtc::AudioProcessing* CreateWebRtcAudioProcessing( - const webrtc::Config& config) { - // libpeerconnection is being compiled as a static lib, use - // webrtc::AudioProcessing directly. - return webrtc::AudioProcessing::Create(config); -} - #else // !LIBPEERCONNECTION_LIB // When being compiled as a shared library, we need to bridge the gap between @@ -98,7 +89,6 @@ webrtc::AudioProcessing* CreateWebRtcAudioProcessing( // Global function pointers to the factory functions in the shared library. CreateWebRtcMediaEngineFunction g_create_webrtc_media_engine = NULL; DestroyWebRtcMediaEngineFunction g_destroy_webrtc_media_engine = NULL; -CreateWebRtcAudioProcessingFunction g_create_webrtc_audio_processing = NULL; // Returns the full or relative path to the libpeerconnection module depending // on what platform we're on. @@ -175,8 +165,8 @@ bool InitializeWebRtcModule() { &AddTraceEvent, &g_create_webrtc_media_engine, &g_destroy_webrtc_media_engine, - &init_diagnostic_logging, - &g_create_webrtc_audio_processing); + &init_diagnostic_logging); + if (init_ok) rtc::SetExtraLoggingInit(init_diagnostic_logging); return init_ok; @@ -200,12 +190,4 @@ void DestroyWebRtcMediaEngine(cricket::MediaEngineInterface* media_engine) { g_destroy_webrtc_media_engine(media_engine); } -webrtc::AudioProcessing* CreateWebRtcAudioProcessing( - const webrtc::Config& config) { - // The same as CreateWebRtcMediaEngine(), we call InitializeWebRtcModule here - // for convenience of tests. - InitializeWebRtcModule(); - return g_create_webrtc_audio_processing(config); -} - #endif // LIBPEERCONNECTION_LIB diff --git a/third_party/libjingle/overrides/init_webrtc.h b/third_party/libjingle/overrides/init_webrtc.h index c29bd71b69d96..714f9c6ad8177 100644 --- a/third_party/libjingle/overrides/init_webrtc.h +++ b/third_party/libjingle/overrides/init_webrtc.h @@ -23,8 +23,6 @@ class WebRtcVideoEncoderFactory; namespace webrtc { class AudioDeviceModule; -class AudioProcessing; -class Config; namespace metrics { class Histogram; } // namespace metrics @@ -53,9 +51,6 @@ typedef void (*DestroyWebRtcMediaEngineFunction)( typedef void (*InitDiagnosticLoggingDelegateFunctionFunction)( void (*DelegateFunction)(const std::string&)); -typedef webrtc::AudioProcessing* (*CreateWebRtcAudioProcessingFunction)( - const webrtc::Config& config); - // A typedef for the main initialize function in libpeerconnection. // This will initialize logging in the module with the proper arguments // as well as provide pointers back to a couple webrtc factory functions. @@ -77,8 +72,7 @@ typedef bool (*InitializeModuleFunction)( webrtc::AddTraceEventPtr trace_add_trace_event, CreateWebRtcMediaEngineFunction* create_media_engine, DestroyWebRtcMediaEngineFunction* destroy_media_engine, - InitDiagnosticLoggingDelegateFunctionFunction* init_diagnostic_logging, - CreateWebRtcAudioProcessingFunction* create_audio_processing); + InitDiagnosticLoggingDelegateFunctionFunction* init_diagnostic_logging); #if !defined(LIBPEERCONNECTION_IMPLEMENTATION) // Load and initialize the shared WebRTC module (libpeerconnection). @@ -87,11 +81,6 @@ typedef bool (*InitializeModuleFunction)( // If not called explicitly, this function will still be called from the main // CreateWebRtcMediaEngine factory function the first time it is called. bool InitializeWebRtcModule(); - -// Return a webrtc::AudioProcessing object. -webrtc::AudioProcessing* CreateWebRtcAudioProcessing( - const webrtc::Config& config); - #endif #endif // THIRD_PARTY_LIBJINGLE_OVERRIDES_INIT_WEBRTC_H_ diff --git a/third_party/libjingle/overrides/initialize_module.cc b/third_party/libjingle/overrides/initialize_module.cc index 1250cfb0ec2f0..09afbc2aed46b 100644 --- a/third_party/libjingle/overrides/initialize_module.cc +++ b/third_party/libjingle/overrides/initialize_module.cc @@ -8,7 +8,6 @@ #include "base/logging.h" #include "init_webrtc.h" #include "talk/media/webrtc/webrtcmediaengine.h" -#include "third_party/webrtc/modules/audio_processing/include/audio_processing.h" #include "webrtc/base/basictypes.h" #include "webrtc/base/logging.h" @@ -99,9 +98,7 @@ bool InitializeModule(const CommandLine& command_line, CreateWebRtcMediaEngineFunction* create_media_engine, DestroyWebRtcMediaEngineFunction* destroy_media_engine, InitDiagnosticLoggingDelegateFunctionFunction* - init_diagnostic_logging, - CreateWebRtcAudioProcessingFunction* - create_audio_processing) { + init_diagnostic_logging) { #if !defined(OS_MACOSX) && !defined(OS_ANDROID) g_alloc = alloc; g_dealloc = dealloc; @@ -115,7 +112,6 @@ bool InitializeModule(const CommandLine& command_line, *create_media_engine = &CreateWebRtcMediaEngine; *destroy_media_engine = &DestroyWebRtcMediaEngine; *init_diagnostic_logging = &rtc::InitDiagnosticLoggingDelegateFunction; - *create_audio_processing = &webrtc::AudioProcessing::Create; if (CommandLine::Init(0, NULL)) { #if !defined(OS_WIN) diff --git a/third_party/libva/va/va.h b/third_party/libva/va/va.h index 845760cbd5370..94550238c2bee 100644 --- a/third_party/libva/va/va.h +++ b/third_party/libva/va/va.h @@ -78,6 +78,7 @@ #ifndef _VA_H_ #define _VA_H_ +#include #include #include @@ -1851,6 +1852,116 @@ VAStatus vaDestroyBuffer ( VABufferID buffer_id ); +/** VA buffer information */ +typedef struct { + /** Buffer handle */ + uintptr_t handle; + /** Buffer type (See VABufferType). */ + uint32_t type; + /** + * Buffer memory type (See VASurfaceAttribMemoryType). + * + * On input to vaLockBuffer(), this field can serve as a hint to + * specify the set of memory types the caller is interested in. On + * successful return from vaLockBuffer(), the field is updated + * with the best matching memory type. + */ + uint32_t mem_type; + /** Size of the underlying buffer. */ + size_t mem_size; +} VABufferInfo; + +/** + * Locks buffer for external API usage. + * + * Locks the VA buffer object buf_id for external API usage like + * EGL or OpenCL (OCL). This function is a synchronization point. This + * means that any pending operation is guaranteed to be completed + * prior to returning from the function. + * + * If the referenced VA buffer object is the backing store of a VA + * surface, then this function acts as if vaSyncSurface() on the + * parent surface was called first. + * + * The VABufferInfo argument shall be zero'ed on input. On + * successful output, the data structure is filled in with all the + * necessary buffer level implementation details like handle, type, + * memory type and memory size. + * + * Note: the external API implementation, or the application, can + * express the memory types it is interested in by filling in the + * mem_type field accordingly. On successful output, the memory type + * that fits best the request and that was used is updated in the + * VABufferInfo data structure. If none of the supplied memory types + * is supported, then a VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE + * error is returned. + * + * The VABufferInfo data is valid until vaUnlockBuffer() is + * called. Besides, no additional operation is allowed on any of the + * buffer parent object until vaUnlockBuffer() is called. e.g. decoding + * into a VA surface backed with the supplied VA buffer object + * buf_id would fail with a VA_STATUS_ERROR_SURFACE_BUSY error. + * + * Possible errors: + * - VA_STATUS_ERROR_UNIMPLEMENTED: the VA driver implementation + * does not support this interface + * - VA_STATUS_ERROR_INVALID_DISPLAY: an invalid display was supplied + * - VA_STATUS_ERROR_INVALID_BUFFER: an invalid buffer was supplied + * - VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE: the implementation + * does not support exporting buffers of the specified type + * - VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE: none of the requested + * memory types in \ref VABufferInfo.mem_type was supported + * + * @param[in] dpy the VA display + * @param[in] buf_id the VA buffer + * @param[in,out] buf_info_ptr the VA buffer information + * @return VA_STATUS_SUCCESS if successful + */ +VAStatus +vaLockBuffer( + VADisplay dpy, + VABufferID buf_id, + VABufferInfo * buf_info_ptr +); + +/** + * Unlocks buffer after usage from external API. + * + * Unlocks the VA buffer object buf_id from external API usage like + * EGL or OpenCL (OCL). This function is a synchronization point. This + * means that any pending operation is guaranteed to be completed + * prior to returning from the function. + * + * The VABufferInfo argument shall point to the original data + * structure that was obtained from vaLockBuffer(), unaltered. This is + * necessary so that the VA driver implementation could deallocate any + * resources that were needed. + * + * In any case, returning from this function invalidates any contents + * in VABufferInfo. i.e. the underlyng buffer handle is no longer + * valid. Therefore, VA driver implementations are free to reset this + * data structure to safe defaults. + * + * Possible errors: + * - VA_STATUS_ERROR_UNIMPLEMENTED: the VA driver implementation + * does not support this interface + * - VA_STATUS_ERROR_INVALID_DISPLAY: an invalid display was supplied + * - VA_STATUS_ERROR_INVALID_BUFFER: an invalid buffer was supplied + * - VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE: the implementation + * does not support exporting buffers of the specified type + * + * @param[in] dpy the VA display + * @param[in] buf_id the VA buffer + * @param[in,out] buf_info_ptr the VA buffer information + * @return VA_STATUS_SUCCESS if successful + */ +VAStatus +vaUnlockBuffer( + VADisplay dpy, + VABufferID buf_id, + VABufferInfo * buf_info_ptr +); + /* Render (Decode) Pictures diff --git a/third_party/libva/va/va_backend.h b/third_party/libva/va/va_backend.h index bd828497dd9f6..150f8ef7d59b4 100644 --- a/third_party/libva/va/va_backend.h +++ b/third_party/libva/va/va_backend.h @@ -420,6 +420,20 @@ struct VADriverVTable VASurfaceAttrib *attrib_list, unsigned int *num_attribs ); + + VAStatus + (*vaLockBuffer)( + VADriverContextP ctx, + VABufferID buf_id, + VABufferInfo * buf_info_ptr + ); + + VAStatus + (*vaUnlockBuffer)( + VADriverContextP ctx, + VABufferID buf_id, + VABufferInfo * buf_info_ptr + ); }; struct VADriverContext diff --git a/tools/generate_stubs/generate_stubs.py b/tools/generate_stubs/generate_stubs.py index 4c0fcac40cdac..a4bc27f112552 100755 --- a/tools/generate_stubs/generate_stubs.py +++ b/tools/generate_stubs/generate_stubs.py @@ -381,7 +381,7 @@ def ExtractModuleName(infile_path): return basename -def ParseSignatures(infile): +def ParseSignaturesReal(infile): """Parses function signatures in the input file. This function parses a file of signatures into a list of dictionaries that @@ -425,6 +425,27 @@ def ParseSignatures(infile): return signatures +# Sometimes additional signatures other than what is exposed to Chromium are +# needed, in particular for ffmpeg. If we ever make a fork of ffmpeg, is +# probably a good idea to remove this patch and add the signatures directly on +# the .sigs file at the dependency repository. In order to expose additional +# signatures of a library foobar, just add a .sig file prefixed with "xwalk_" at +# the root folder of the directory containing this script. +def ParseSignatures(infile): + signatures = ParseSignaturesReal(infile) + + xwalk_sig_dir = os.path.dirname(os.path.realpath(__file__)) + xwalk_sig_file = os.path.join(xwalk_sig_dir, + 'xwalk_' + os.path.basename(infile.name)) + + if os.path.exists(xwalk_sig_file): + xwalk_infile = open(xwalk_sig_file, 'r') + signatures += ParseSignaturesReal(xwalk_infile) + xwalk_infile.close() + + return signatures + + def WriteWindowsDefFile(module_name, signatures, outfile): """Writes a windows def file to the given output file object. diff --git a/tools/generate_stubs/xwalk_ffmpegsumo.sigs b/tools/generate_stubs/xwalk_ffmpegsumo.sigs new file mode 100644 index 0000000000000..ab8f2f940360a --- /dev/null +++ b/tools/generate_stubs/xwalk_ffmpegsumo.sigs @@ -0,0 +1,7 @@ +# Copyright (c) 2013 Intel Corporation. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +AVCodec *av_codec_next(const AVCodec *c); +int av_codec_is_encoder(const AVCodec *c); +int av_codec_is_decoder(const AVCodec *c); diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index e077c0a5dd20c..b78e2cca3305b 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml @@ -17334,6 +17334,9 @@ Therefore, the affected-histogram name has to have at least one dot in it. + + Deprecated as of 11/2014. Replaced by Net.QuicInchoateClientHelloReason. + rtenneti@chromium.org The reason (the state of the server config) for sending inchoate ClientHello @@ -17399,6 +17402,15 @@ Therefore, the affected-histogram name has to have at least one dot in it. + + rtenneti@chromium.org + + The reason (the state of the server config) for sending inchoate ClientHello + to the server. + + + rch@chromium.org The number of client hello messages sent. @@ -17448,6 +17460,15 @@ Therefore, the affected-histogram name has to have at least one dot in it. Time spent to load QUIC server information from disk cache. + + rtenneti@chromium.org + + The state of the QUIC server information when it's loaded from the disk + cache. + + + rtenneti@chromium.org @@ -17456,6 +17477,16 @@ Therefore, the affected-histogram name has to have at least one dot in it. + + rtenneti@chromium.org + + The number of times AlternateProtocolMap supports QUIC, but there is no QUIC + server information in the disk cache. This is recorded whenever QUIC server + information is loaded from the disk cache. + + + rch@chromium.org @@ -22566,6 +22597,10 @@ Therefore, the affected-histogram name has to have at least one dot in it. gcasto@chromium.org vabr@chromium.org + + Deprecated as of 11/11/14. New statistic is + PasswordManager.TimesPasswordUsed.AutoGenerated. + The number of times each generated password has been used to log in. Recorded by iterating over stored passwords once per run. This information @@ -25112,6 +25147,32 @@ Therefore, the affected-histogram name has to have at least one dot in it. + + tommycli@chromium.org + + Aspect ratio of Flash plugins users click at least once. The aspect ratio is + multiplied by 100 and stored as a rounded integer. + + + + + tommycli@chromium.org + Height of Flash plugins users click at least once. + + + + tommycli@chromium.org + Width of Flash plugins users click at least once. + + + + tommycli@chromium.org + + Collects the sizes of all loaded Flash plugin instances. This is for + determining the prevalence of tiny flash plugin instances. + + + Please list the metric's owners. Add more owner tags as needed. Record usage of PPB_Flash.Navigate() Pepper API. @@ -25123,7 +25184,7 @@ Therefore, the affected-histogram name has to have at least one dot in it. Collects Flash usage data. - tommycli@chromium.org @@ -25135,7 +25196,7 @@ Therefore, the affected-histogram name has to have at least one dot in it. - tommycli@chromium.org @@ -41293,6 +41354,11 @@ Therefore, the affected-histogram name has to have at least one dot in it. + + + + + @@ -43352,6 +43418,8 @@ Therefore, the affected-histogram name has to have at least one dot in it. + @@ -45907,6 +45975,13 @@ Therefore, the affected-histogram name has to have at least one dot in it. + + + + + + + Number of browser processes that have started at least one NPAPI Flash @@ -47852,6 +47927,7 @@ To add a new entry, add it with any value and run test to compute valid value. + @@ -48016,6 +48092,7 @@ To add a new entry, add it with any value and run test to compute valid value. + @@ -52557,6 +52634,7 @@ To add a new entry, add it with any value and run test to compute valid value. + @@ -58409,6 +58487,10 @@ To add a new entry, add it with any value and run test to compute valid value. + @@ -58554,8 +58636,20 @@ To add a new entry, add it with any value and run test to compute valid value. + + + + + + + + + + + + diff --git a/ui/accessibility/ax_enums.idl b/ui/accessibility/ax_enums.idl index ede09efc364df..1c53875b46772 100644 --- a/ui/accessibility/ax_enums.idl +++ b/ui/accessibility/ax_enums.idl @@ -56,6 +56,9 @@ show, // Remove: http://crbug.com/392502 text_changed, text_selection_changed, + tree_changed, // Accessibility tree changed. Don't + // explicitly fire an accessibility event, + // only implicitly due to the change. value_changed }; diff --git a/ui/android/java/res/layout/dropdown_item.xml b/ui/android/java/res/layout/dropdown_item.xml index 248b4dc69a02c..1652fcb757985 100644 --- a/ui/android/java/res/layout/dropdown_item.xml +++ b/ui/android/java/res/layout/dropdown_item.xml @@ -11,11 +11,12 @@ android:layout_height="wrap_content" android:gravity="center_vertical"> - + android:orientation="vertical" + android:gravity="center_vertical"> mAnchorWidth) { setContentWidth(contentWidth); final Rect displayFrame = new Rect(); diff --git a/ui/android/java/src/org/chromium/ui/widget/TextViewWithClickableSpans.java b/ui/android/java/src/org/chromium/ui/widget/TextViewWithClickableSpans.java index 64488043f2760..5c76f3a888cb1 100644 --- a/ui/android/java/src/org/chromium/ui/widget/TextViewWithClickableSpans.java +++ b/ui/android/java/src/org/chromium/ui/widget/TextViewWithClickableSpans.java @@ -5,22 +5,31 @@ package org.chromium.ui.widget; import android.content.Context; +import android.os.Bundle; +import android.text.Layout; import android.text.SpannableString; import android.text.style.ClickableSpan; import android.util.AttributeSet; import android.view.Menu; import android.view.MenuItem; +import android.view.MotionEvent; import android.view.View; +import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.AccessibilityNodeInfo; import android.widget.PopupMenu; import android.widget.TextView; /** - * ClickableSpan isn't accessible by default, so we create a simple subclass - * of TextView that addresses this by adding click and longpress handlers. - * If there's only one ClickableSpan, we activate it. If there's more than - * one, we pop up a Spinner to disambiguate. + * ClickableSpan isn't accessible by default, so we create a subclass + * of TextView that tries to handle the case where a user clicks on a view + * and not directly on one of the clickable spans. We do nothing if it's a + * touch event directly on a ClickableSpan. Otherwise if there's only one + * ClickableSpan, we activate it. If there's more than one, we pop up a + * PopupMenu to disambiguate. */ public class TextViewWithClickableSpans extends TextView { + private AccessibilityManager mAccessibilityManager; + public TextViewWithClickableSpans(Context context) { super(context); init(); @@ -37,21 +46,74 @@ public TextViewWithClickableSpans(Context context, AttributeSet attrs, int defSt } private void init() { - setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - handleClick(); - } - }); + mAccessibilityManager = (AccessibilityManager) + getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { + if (!mAccessibilityManager.isTouchExplorationEnabled()) { + return false; + } openDisambiguationMenu(); return true; } }); } + @Override + public boolean performAccessibilityAction(int action, Bundle arguments) { + // BrailleBack will generate an accessibility click event directly + // on this view, make sure we handle that correctly. + if (action == AccessibilityNodeInfo.ACTION_CLICK) { + handleAccessibilityClick(); + return true; + } + return super.performAccessibilityAction(action, arguments); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + boolean superResult = super.onTouchEvent(event); + + if (event.getAction() != MotionEvent.ACTION_UP + && mAccessibilityManager.isTouchExplorationEnabled() + && !touchIntersectsAnyClickableSpans(event)) { + handleAccessibilityClick(); + return true; + } + + return superResult; + } + + private boolean touchIntersectsAnyClickableSpans(MotionEvent event) { + // This logic is borrowed from android.text.method.LinkMovementMethod. + // + // ClickableSpan doesn't stop propagation of the event in its click handler, + // so we should only try to simplify clicking on a clickable span if the touch event + // isn't already over a clickable span. + + CharSequence text = getText(); + if (!(text instanceof SpannableString)) return false; + SpannableString spannable = (SpannableString) text; + + int x = (int) event.getX(); + int y = (int) event.getY(); + + x -= getTotalPaddingLeft(); + y -= getTotalPaddingTop(); + + x += getScrollX(); + y += getScrollY(); + + Layout layout = getLayout(); + int line = layout.getLineForVertical(y); + int off = layout.getOffsetForHorizontal(line, x); + + ClickableSpan[] clickableSpans = + spannable.getSpans(off, off, ClickableSpan.class); + return clickableSpans.length > 0; + } + private ClickableSpan[] getClickableSpans() { CharSequence text = getText(); if (!(text instanceof SpannableString)) return null; @@ -60,7 +122,7 @@ private ClickableSpan[] getClickableSpans() { return spannable.getSpans(0, spannable.length(), ClickableSpan.class); } - private void handleClick() { + private void handleAccessibilityClick() { ClickableSpan[] clickableSpans = getClickableSpans(); if (clickableSpans == null || clickableSpans.length == 0) { return; diff --git a/ui/base/ui_base_switches.cc b/ui/base/ui_base_switches.cc index 2163397ccf393..24d0d553dd04d 100644 --- a/ui/base/ui_base_switches.cc +++ b/ui/base/ui_base_switches.cc @@ -27,6 +27,10 @@ const char kDisableTouchDragDrop[] = "disable-touch-drag-drop"; // Disables controls that support touch base text editing. const char kDisableTouchEditing[] = "disable-touch-editing"; +// Enables a zoomed popup bubble that allows the user to select a link. +const char kEnableLinkDisambiguationPopup[] = + "enable-link-disambiguation-popup"; + // Enables an experimental focus manager to track text input clients. const char kEnableTextInputFocusManager[] = "enable-text-input-focus-manager"; diff --git a/ui/base/ui_base_switches.h b/ui/base/ui_base_switches.h index 629f9afd8fe4a..b4d503b993614 100644 --- a/ui/base/ui_base_switches.h +++ b/ui/base/ui_base_switches.h @@ -21,6 +21,7 @@ UI_BASE_EXPORT extern const char kDisableTextInputFocusManager[]; UI_BASE_EXPORT extern const char kDisableTouchAdjustment[]; UI_BASE_EXPORT extern const char kDisableTouchDragDrop[]; UI_BASE_EXPORT extern const char kDisableTouchEditing[]; +UI_BASE_EXPORT extern const char kEnableLinkDisambiguationPopup[]; UI_BASE_EXPORT extern const char kEnableTextInputFocusManager[]; UI_BASE_EXPORT extern const char kEnableTouchDragDrop[]; UI_BASE_EXPORT extern const char kEnableTouchEditing[]; diff --git a/ui/base/ui_base_switches_util.cc b/ui/base/ui_base_switches_util.cc index 58b85c7ab4639..7a89264a4c2e7 100644 --- a/ui/base/ui_base_switches_util.cc +++ b/ui/base/ui_base_switches_util.cc @@ -9,6 +9,18 @@ namespace switches { +bool IsLinkDisambiguationPopupEnabled() { +#if defined(OS_ANDROID) + return true; +#else + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableLinkDisambiguationPopup)) { + return true; + } + return false; +#endif +} + bool IsTextInputFocusManagerEnabled() { return CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableTextInputFocusManager); diff --git a/ui/base/ui_base_switches_util.h b/ui/base/ui_base_switches_util.h index de08d1c4e0f80..213aed6008767 100644 --- a/ui/base/ui_base_switches_util.h +++ b/ui/base/ui_base_switches_util.h @@ -9,6 +9,7 @@ namespace switches { +UI_BASE_EXPORT bool IsLinkDisambiguationPopupEnabled(); UI_BASE_EXPORT bool IsTextInputFocusManagerEnabled(); UI_BASE_EXPORT bool IsTouchDragDropEnabled(); UI_BASE_EXPORT bool IsTouchEditingEnabled(); diff --git a/ui/base/win/shell.cc b/ui/base/win/shell.cc index ee656edbfe559..91eaf9313b78d 100644 --- a/ui/base/win/shell.cc +++ b/ui/base/win/shell.cc @@ -10,6 +10,7 @@ #include #include "base/command_line.h" +#include "base/debug/alias.h" #include "base/files/file_path.h" #include "base/native_library.h" #include "base/strings/string_util.h" @@ -146,7 +147,9 @@ bool IsAeroGlassEnabled() { switches::kDisableDwmComposition)) return false; - if (base::win::GetVersion() < base::win::VERSION_VISTA) + base::win::Version version = base::win::GetVersion(); + base::debug::Alias(&version); // TODO(scottmg): http://crbug.com/431549. + if (version < base::win::VERSION_VISTA) return false; // If composition is not enabled, we behave like on XP. BOOL enabled = FALSE; diff --git a/ui/events/devices/x11/touch_factory_x11.cc b/ui/events/devices/x11/touch_factory_x11.cc index e6713cd14bf49..599cf8e8face0 100644 --- a/ui/events/devices/x11/touch_factory_x11.cc +++ b/ui/events/devices/x11/touch_factory_x11.cc @@ -123,7 +123,7 @@ void TouchFactory::UpdateDeviceList(Display* display) { DeviceListCacheX11::GetInstance()->GetXI2DeviceList(display); for (int i = 0; i < xi_dev_list.count; i++) { XIDeviceInfo* devinfo = xi_dev_list.devices + i; - if (devinfo->use == XIFloatingSlave || devinfo->use == XIMasterPointer) { + if (devinfo->use == XIFloatingSlave || devinfo->use == XISlavePointer) { #if defined(USE_XI2_MT) for (int k = 0; k < devinfo->num_classes; ++k) { XIAnyClassInfo* xiclassinfo = devinfo->classes[k]; diff --git a/ui/file_manager/file_manager/background/js/volume_manager.js b/ui/file_manager/file_manager/background/js/volume_manager.js index e5c645bf615c5..13d91b37445eb 100644 --- a/ui/file_manager/file_manager/background/js/volume_manager.js +++ b/ui/file_manager/file_manager/background/js/volume_manager.js @@ -464,7 +464,8 @@ function VolumeManager() { */ this.driveConnectionState_ = { type: VolumeManagerCommon.DriveConnectionType.OFFLINE, - reason: VolumeManagerCommon.DriveConnectionReason.NO_SERVICE + reason: VolumeManagerCommon.DriveConnectionReason.NO_SERVICE, + hasCellularNetworkAccess: false }; chrome.fileManagerPrivate.onDriveConnectionStatusChanged.addListener( diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js index e2ed10ebfd284..3f3597f675492 100644 --- a/ui/file_manager/file_manager/foreground/js/file_manager.js +++ b/ui/file_manager/file_manager/foreground/js/file_manager.js @@ -1941,7 +1941,7 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52; * @return {boolean} True if those setting items should be shown. */ FileManager.prototype.shouldShowDriveSettings = function() { - return this.isOnDrive() && this.isSecretGearMenuShown_; + return this.isOnDrive(); }; /** diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js index 0b96747f9a939..58d4e1e73c643 100644 --- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js +++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js @@ -508,7 +508,9 @@ CommandHandler.COMMANDS_['drive-sync-settings'] = /** @type {Command} */ ({ * @param {!FileManager} fileManager FileManager to use. */ canExecute: function(event, fileManager) { - event.canExecute = fileManager.shouldShowDriveSettings(); + event.canExecute = fileManager.shouldShowDriveSettings() && + fileManager.volumeManager.getDriveConnectionState(). + hasCellularNetworkAccess; event.command.setHidden(!event.canExecute); } }); diff --git a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js index 78d40041f492e..cb0c6b1caa29e 100644 --- a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js +++ b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js @@ -200,7 +200,10 @@ FileTransferController.prototype = { var externalFileUrl; for (var i = 0; i < this.selectedEntries_.length; i++) { var url = this.selectedEntries_[i].toURL(); - dataTransfer.items.add(this.selectedAsyncData_[url].file); + if (!this.selectedAsyncData_[url]) + continue; + if (this.selectedAsyncData_[url].file) + dataTransfer.items.add(this.selectedAsyncData_[url].file); if (!externalFileUrl) externalFileUrl = this.selectedAsyncData_[url].externalFileUrl; } diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js index edb3dc2a3e88c..0df02c33ed340 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js +++ b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js @@ -209,7 +209,10 @@ FileManagerUI.prototype.initAdditionalUI = function(table, grid, previewPanel) { */ FileManagerUI.prototype.relayout = function() { this.locationLine.truncate(); - this.listContainer.currentView.relayout(); + if (this.listContainer.currentListType !== + ListContainer.ListType.UNINITIALIZED) { + this.listContainer.currentView.relayout(); + } }; /** @@ -221,13 +224,13 @@ FileManagerUI.prototype.setCurrentListType = function(listType) { switch (listType) { case ListContainer.ListType.DETAIL: - this.toggleViewButton.classList.add('table'); - this.toggleViewButton.classList.remove('grid'); + this.toggleViewButton.classList.remove('table'); + this.toggleViewButton.classList.add('grid'); break; case ListContainer.ListType.THUMBNAIL: - this.toggleViewButton.classList.add('grid'); - this.toggleViewButton.classList.remove('table'); + this.toggleViewButton.classList.remove('grid'); + this.toggleViewButton.classList.add('table'); break; default: diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc index 1ca874a0e461f..87e650b8cf310 100644 --- a/ui/gfx/render_text.cc +++ b/ui/gfx/render_text.cc @@ -398,9 +398,14 @@ RenderText::~RenderText() { } RenderText* RenderText::CreateInstance() { - return CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDisableHarfBuzzRenderText) ? CreateNativeInstance() : - new RenderTextHarfBuzz; +#if defined(OS_MACOSX) && !defined(TOOLKIT_VIEWS) + static const bool use_harfbuzz = CommandLine::ForCurrentProcess()-> + HasSwitch(switches::kEnableHarfBuzzRenderText); +#else + static const bool use_harfbuzz = !CommandLine::ForCurrentProcess()-> + HasSwitch(switches::kDisableHarfBuzzRenderText); +#endif + return use_harfbuzz ? new RenderTextHarfBuzz : CreateNativeInstance(); } void RenderText::SetText(const base::string16& text) { diff --git a/ui/gfx/render_text_harfbuzz.cc b/ui/gfx/render_text_harfbuzz.cc index 1aba788a0eb14..768be0bc4f50b 100644 --- a/ui/gfx/render_text_harfbuzz.cc +++ b/ui/gfx/render_text_harfbuzz.cc @@ -1206,11 +1206,9 @@ bool RenderTextHarfBuzz::ShapeRunWithFont(internal::TextRunHarfBuzz* run, const SkScalar y_offset = SkFixedToScalar(hb_positions[i].y_offset); run->positions[i].set(run->width + x_offset, -y_offset); run->width += SkFixedToScalar(hb_positions[i].x_advance); -#if defined(OS_LINUX) - // Match Pango's glyph rounding logic on Linux. + // Round run widths if subpixel positioning is off to match native behavior. if (!run->render_params.subpixel_positioning) run->width = std::floor(run->width + 0.5f); -#endif } hb_buffer_destroy(buffer); diff --git a/ui/gfx/render_text_unittest.cc b/ui/gfx/render_text_unittest.cc index 876c8a8e0ba68..859689b5febce 100644 --- a/ui/gfx/render_text_unittest.cc +++ b/ui/gfx/render_text_unittest.cc @@ -2332,7 +2332,7 @@ TEST_F(RenderTextTest, StringFitsOwnWidth) { #if !defined(OS_WIN) // Ensure that RenderText examines all of the fonts in its FontList before // falling back to other fonts. -TEST_F(RenderTextTest, FontListFallback) { +TEST_F(RenderTextTest, HarfBuzz_FontListFallback) { // Double-check that the requested fonts are present. FontList font_list("Arial, Symbol, 12px"); const std::vector& fonts = font_list.GetFonts(); @@ -2344,11 +2344,11 @@ TEST_F(RenderTextTest, FontListFallback) { // "⊕" (CIRCLED PLUS) should be rendered with Symbol rather than falling back // to some other font that's present on the system. - scoped_ptr render_text(RenderText::CreateInstance()); - render_text->SetFontList(font_list); - render_text->SetText(UTF8ToUTF16("\xE2\x8A\x95")); + RenderTextHarfBuzz render_text; + render_text.SetFontList(font_list); + render_text.SetText(UTF8ToUTF16("\xE2\x8A\x95")); const std::vector spans = - render_text->GetFontSpansForTesting(); + render_text.GetFontSpansForTesting(); ASSERT_EQ(static_cast(1), spans.size()); EXPECT_EQ("Symbol", spans[0].first.GetFontName()); } diff --git a/ui/gl/gl.gyp b/ui/gl/gl.gyp index cd0a8526aef30..d698dbc43db15 100644 --- a/ui/gl/gl.gyp +++ b/ui/gl/gl.gyp @@ -301,7 +301,6 @@ }], ['use_ozone==1', { 'dependencies': [ - '../ozone/ozone.gyp:ozone', '../ozone/ozone.gyp:ozone_base', ], }], diff --git a/ui/gl/gl_context.cc b/ui/gl/gl_context.cc index 533b7d3146e89..e35806917f3e1 100644 --- a/ui/gl/gl_context.cc +++ b/ui/gl/gl_context.cc @@ -82,6 +82,10 @@ bool GLContext::GetTotalGpuMemory(size_t* bytes) { void GLContext::SetSafeToForceGpuSwitch() { } +bool GLContext::ForceGpuSwitchIfNeeded() { + return true; +} + void GLContext::SetUnbindFboOnMakeCurrent() { NOTIMPLEMENTED(); } @@ -199,6 +203,8 @@ void GLContext::SetupForVirtualization() { bool GLContext::MakeVirtuallyCurrent( GLContext* virtual_context, GLSurface* surface) { DCHECK(virtual_gl_api_); + if (!ForceGpuSwitchIfNeeded()) + return false; return virtual_gl_api_->MakeCurrent(virtual_context, surface); } diff --git a/ui/gl/gl_context.h b/ui/gl/gl_context.h index 372f51380e80c..cdebd686b33ee 100644 --- a/ui/gl/gl_context.h +++ b/ui/gl/gl_context.h @@ -90,6 +90,10 @@ class GL_EXPORT GLContext : public base::RefCounted { // transitioning can cause corruption and hangs (OS X only). virtual void SetSafeToForceGpuSwitch(); + // Attempt to force the context to move to the GPU of its sharegroup. Return + // false only in the event of an unexpected error on the context. + virtual bool ForceGpuSwitchIfNeeded(); + // Indicate that the real context switches should unbind the FBO first // (For an Android work-around only). virtual void SetUnbindFboOnMakeCurrent(); diff --git a/ui/gl/gl_context_cgl.cc b/ui/gl/gl_context_cgl.cc index 10f854aaccda3..277780a3b2447 100644 --- a/ui/gl/gl_context_cgl.cc +++ b/ui/gl/gl_context_cgl.cc @@ -136,7 +136,7 @@ void GLContextCGL::Destroy() { } } -bool GLContextCGL::MakeCurrent(GLSurface* surface) { +bool GLContextCGL::ForceGpuSwitchIfNeeded() { DCHECK(context_); // The call to CGLSetVirtualScreen can hang on some AMD drivers @@ -174,6 +174,14 @@ bool GLContextCGL::MakeCurrent(GLSurface* surface) { renderer_id_ = renderer_id; } } + return true; +} + +bool GLContextCGL::MakeCurrent(GLSurface* surface) { + DCHECK(context_); + + if (!ForceGpuSwitchIfNeeded()) + return false; if (IsCurrent(surface)) return true; diff --git a/ui/gl/gl_context_cgl.h b/ui/gl/gl_context_cgl.h index beeb9f90a3a36..456ea08c53f0f 100644 --- a/ui/gl/gl_context_cgl.h +++ b/ui/gl/gl_context_cgl.h @@ -29,6 +29,7 @@ class GLContextCGL : public GLContextReal { void SetSwapInterval(int interval) override; bool GetTotalGpuMemory(size_t* bytes) override; void SetSafeToForceGpuSwitch() override; + bool ForceGpuSwitchIfNeeded() override; protected: ~GLContextCGL() override; diff --git a/ui/gl/gl_context_egl.cc b/ui/gl/gl_context_egl.cc index 41c10dcff3cd5..52777de4d40b4 100644 --- a/ui/gl/gl_context_egl.cc +++ b/ui/gl/gl_context_egl.cc @@ -112,6 +112,10 @@ bool GLContextEGL::MakeCurrent(GLSurface* surface) { return false; } +#if defined(USE_OZONE) + eglSwapInterval(display_, 0); +#endif + // Set this as soon as the context is current, since we might call into GL. SetRealGLApi(); diff --git a/ui/login/account_picker/user_pod_row.css b/ui/login/account_picker/user_pod_row.css index 246c1fbb2e3dd..780fec911d216 100644 --- a/ui/login/account_picker/user_pod_row.css +++ b/ui/login/account_picker/user_pod_row.css @@ -259,6 +259,21 @@ html[dir=rtl] .main-pane { background-image: url('chrome://theme/IDR_EASY_UNLOCK_LOCKED_PRESSED'); } +.custom-icon-locked-to-be-activated { + background-image: + url('chrome://theme/IDR_EASY_UNLOCK_LOCKED_TO_BE_ACTIVATED'); +} + +.custom-icon-locked-to-be-activated.icon-with-tooltip:hover { + background-image: + url('chrome://theme/IDR_EASY_UNLOCK_LOCKED_TO_BE_ACTIVATED_HOVER'); +} + +.custom-icon-locked-to-be-activated.interactive-custom-icon:active { + background-image: + url('chrome://theme/IDR_EASY_UNLOCK_LOCKED_TO_BE_ACTIVATED_PRESSED'); +} + .custom-icon-locked-with-proximity-hint { background-image: url('chrome://theme/IDR_EASY_UNLOCK_LOCKED_WITH_PROXIMITY_HINT'); @@ -299,6 +314,12 @@ html[dir=rtl] .main-pane { url('chrome://theme/IDR_EASY_UNLOCK_LOCKED') url('chrome://theme/IDR_EASY_UNLOCK_LOCKED_HOVER') url('chrome://theme/IDR_EASY_UNLOCK_LOCKED_PRESSED') + url('chrome://theme/IDR_EASY_UNLOCK_LOCKED_TO_BE_ACTIVATED') + url('chrome://theme/IDR_EASY_UNLOCK_LOCKED_TO_BE_ACTIVATED_HOVER') + url('chrome://theme/IDR_EASY_UNLOCK_LOCKED_TO_BE_ACTIVATED_PRESSED') + url('chrome://theme/IDR_EASY_UNLOCK_LOCKED_WITH_PROXIMITY_HINT') + url('chrome://theme/IDR_EASY_UNLOCK_LOCKED_WITH_PROXIMITY_HINT_HOVER') + url('chrome://theme/IDR_EASY_UNLOCK_LOCKED_WITH_PROXIMITY_HINT_PRESSED') url('chrome://theme/IDR_EASY_UNLOCK_UNLOCKED') url('chrome://theme/IDR_EASY_UNLOCK_UNLOCKED_HOVER') url('chrome://theme/IDR_EASY_UNLOCK_UNLOCKED_PRESSED'); diff --git a/ui/login/account_picker/user_pod_row.js b/ui/login/account_picker/user_pod_row.js index ec32f89060832..f4adf573260ed 100644 --- a/ui/login/account_picker/user_pod_row.js +++ b/ui/login/account_picker/user_pod_row.js @@ -191,6 +191,8 @@ cr.define('login', function() { */ UserPodCustomIcon.ICONS = [ {id: 'locked', class: 'custom-icon-locked'}, + {id: 'locked-to-be-activated', + class: 'custom-icon-locked-to-be-activated'}, {id: 'locked-with-proximity-hint', class: 'custom-icon-locked-with-proximity-hint'}, {id: 'unlocked', class: 'custom-icon-unlocked'}, diff --git a/ui/message_center/BUILD.gn b/ui/message_center/BUILD.gn index 19f7ccdf4bb0d..31e9a89120a21 100644 --- a/ui/message_center/BUILD.gn +++ b/ui/message_center/BUILD.gn @@ -24,7 +24,7 @@ component("message_center") { defines = [ "MESSAGE_CENTER_IMPLEMENTATION" ] - if (enable_notifications) { + if (enable_notifications && !is_android) { sources = [ "cocoa/notification_controller.h", "cocoa/notification_controller.mm", @@ -197,7 +197,7 @@ test("message_center_unittests") { "//url", ] - if (enable_notifications) { + if (enable_notifications && !is_android) { sources += [ "cocoa/notification_controller_unittest.mm", "cocoa/popup_collection_unittest.mm", @@ -232,5 +232,5 @@ test("message_center_unittests") { "//ui/views:test_support", ] } - } # enable_notifications + } # enable_notifications && !is_android } diff --git a/ui/message_center/views/message_center_view.cc b/ui/message_center/views/message_center_view.cc index b9b6f169bea41..983febf83103e 100644 --- a/ui/message_center/views/message_center_view.cc +++ b/ui/message_center/views/message_center_view.cc @@ -54,13 +54,6 @@ const int kAnimateClearingNextNotificationDelayMS = 40; const int kDefaultAnimationDurationMs = 120; const int kDefaultFrameRateHz = 60; - -void SetViewHierarchyEnabled(views::View* view, bool enabled) { - for (int i = 0; i < view->child_count(); i++) - SetViewHierarchyEnabled(view->child_at(i), enabled); - view->SetEnabled(enabled); -} - } // namespace class NoNotificationMessageView : public views::View { @@ -692,13 +685,13 @@ void MessageCenterView::ClearAllNotifications() { if (is_closing_) return; - SetViewHierarchyEnabled(scroller_, false); + scroller_->SetEnabled(false); button_bar_->SetAllButtonsEnabled(false); message_list_view_->ClearAllNotifications(scroller_->GetVisibleRect()); } void MessageCenterView::OnAllNotificationsCleared() { - SetViewHierarchyEnabled(scroller_, true); + scroller_->SetEnabled(true); button_bar_->SetAllButtonsEnabled(true); button_bar_->SetCloseAllButtonEnabled(false); message_center_->RemoveAllVisibleNotifications(true); // Action by user. @@ -870,13 +863,12 @@ void MessageCenterView::OnNotificationRemoved(const std::string& id, next_focused_view = message_list_view_->child_at(index - 1); if (next_focused_view) { - if (view->IsCloseButtonFocused()) { + if (view->IsCloseButtonFocused()) // Safe cast since all views in MessageListView are MessageViews. static_cast( next_focused_view)->RequestFocusOnCloseButton(); - } else { + else next_focused_view->RequestFocus(); - } } } } diff --git a/ui/platform_window/platform_window.h b/ui/platform_window/platform_window.h index d5f5750e213f5..4642c10b529ab 100644 --- a/ui/platform_window/platform_window.h +++ b/ui/platform_window/platform_window.h @@ -22,8 +22,21 @@ class PlatformWindowDelegate; // underlying platform windowing system (i.e. X11/Win/OSX). class PlatformWindow { public: + enum PlatformWindowType { + PLATFORM_WINDOW_UNKNOWN, + PLATFORM_WINDOW_TYPE_TOOLTIP, + PLATFORM_WINDOW_TYPE_POPUP, + PLATFORM_WINDOW_TYPE_MENU, + PLATFORM_WINDOW_TYPE_BUBBLE, + PLATFORM_WINDOW_TYPE_WINDOW, + PLATFORM_WINDOW_TYPE_WINDOW_FRAMELESS + }; + virtual ~PlatformWindow() {} + virtual void InitPlatformWindow(PlatformWindowType type, + gfx::AcceleratedWidget parent_window) { } + virtual void Show() = 0; virtual void Hide() = 0; virtual void Close() = 0; diff --git a/ui/resources/default_100_percent/common/easy_unlock_locked_to_be_activated.png b/ui/resources/default_100_percent/common/easy_unlock_locked_to_be_activated.png new file mode 100644 index 0000000000000..73a83c0359a07 Binary files /dev/null and b/ui/resources/default_100_percent/common/easy_unlock_locked_to_be_activated.png differ diff --git a/ui/resources/default_100_percent/common/easy_unlock_locked_to_be_activated_hover.png b/ui/resources/default_100_percent/common/easy_unlock_locked_to_be_activated_hover.png new file mode 100644 index 0000000000000..45abc6e7604ee Binary files /dev/null and b/ui/resources/default_100_percent/common/easy_unlock_locked_to_be_activated_hover.png differ diff --git a/ui/resources/default_100_percent/common/easy_unlock_locked_to_be_activated_pressed.png b/ui/resources/default_100_percent/common/easy_unlock_locked_to_be_activated_pressed.png new file mode 100644 index 0000000000000..a41cbeb77803e Binary files /dev/null and b/ui/resources/default_100_percent/common/easy_unlock_locked_to_be_activated_pressed.png differ diff --git a/ui/resources/default_200_percent/common/easy_unlock_locked_to_be_activated.png b/ui/resources/default_200_percent/common/easy_unlock_locked_to_be_activated.png new file mode 100644 index 0000000000000..37c36b95d0ff7 Binary files /dev/null and b/ui/resources/default_200_percent/common/easy_unlock_locked_to_be_activated.png differ diff --git a/ui/resources/default_200_percent/common/easy_unlock_locked_to_be_activated_hover.png b/ui/resources/default_200_percent/common/easy_unlock_locked_to_be_activated_hover.png new file mode 100644 index 0000000000000..4b488c295b916 Binary files /dev/null and b/ui/resources/default_200_percent/common/easy_unlock_locked_to_be_activated_hover.png differ diff --git a/ui/resources/default_200_percent/common/easy_unlock_locked_to_be_activated_pressed.png b/ui/resources/default_200_percent/common/easy_unlock_locked_to_be_activated_pressed.png new file mode 100644 index 0000000000000..dd7de167f224f Binary files /dev/null and b/ui/resources/default_200_percent/common/easy_unlock_locked_to_be_activated_pressed.png differ diff --git a/ui/resources/ui_resources.grd b/ui/resources/ui_resources.grd index 7b33c238c9b8e..cadb5177f75e5 100644 --- a/ui/resources/ui_resources.grd +++ b/ui/resources/ui_resources.grd @@ -270,6 +270,9 @@ + + + diff --git a/ui/views/controls/label.cc b/ui/views/controls/label.cc index 1078d0b5a8a84..9d71a98bcbe4c 100644 --- a/ui/views/controls/label.cc +++ b/ui/views/controls/label.cc @@ -437,7 +437,10 @@ gfx::Rect Label::GetTextBounds() const { NOTREACHED(); break; } - text_size.set_height(available.height()); + if (!multi_line_) + text_size.set_height(available.height()); + // Support vertical centering of multi-line labels: http://crbug.com/429595 + origin.Offset(0, std::max(0, (available.height() - text_size.height())) / 2); return gfx::Rect(origin, text_size); } diff --git a/ui/views/controls/label_unittest.cc b/ui/views/controls/label_unittest.cc index 076ec4648c96b..3a99557ad7157 100644 --- a/ui/views/controls/label_unittest.cc +++ b/ui/views/controls/label_unittest.cc @@ -523,9 +523,9 @@ TEST_F(LabelTest, DrawMultiLineString) { label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags); EXPECT_EQ(label.text(), paint_text); EXPECT_EQ(extra.width() / 2, text_bounds.x()); - EXPECT_EQ(0, text_bounds.y()); + EXPECT_EQ(extra.height() / 2, text_bounds.y()); EXPECT_GT(text_bounds.width(), kMinTextDimension); - EXPECT_EQ(text_bounds.height(), label.height()); + EXPECT_GT(text_bounds.height(), kMinTextDimension); int expected_flags = gfx::Canvas::MULTI_LINE | gfx::Canvas::TEXT_ALIGN_CENTER | gfx::Canvas::FORCE_LTR_DIRECTIONALITY; @@ -541,9 +541,9 @@ TEST_F(LabelTest, DrawMultiLineString) { label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags); EXPECT_EQ(label.text(), paint_text); EXPECT_EQ(0, text_bounds.x()); - EXPECT_EQ(0, text_bounds.y()); + EXPECT_EQ(extra.height() / 2, text_bounds.y()); EXPECT_GT(text_bounds.width(), kMinTextDimension); - EXPECT_EQ(text_bounds.height(), label.height()); + EXPECT_GT(text_bounds.height(), kMinTextDimension); expected_flags = gfx::Canvas::MULTI_LINE | gfx::Canvas::TEXT_ALIGN_LEFT | gfx::Canvas::FORCE_LTR_DIRECTIONALITY; @@ -558,9 +558,9 @@ TEST_F(LabelTest, DrawMultiLineString) { label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags); EXPECT_EQ(label.text(), paint_text); EXPECT_EQ(extra.width(), text_bounds.x()); - EXPECT_EQ(0, text_bounds.y()); + EXPECT_EQ(extra.height() / 2, text_bounds.y()); EXPECT_GT(text_bounds.width(), kMinTextDimension); - EXPECT_EQ(text_bounds.height(), label.height()); + EXPECT_GT(text_bounds.height(), kMinTextDimension); expected_flags = gfx::Canvas::MULTI_LINE | gfx::Canvas::TEXT_ALIGN_RIGHT | gfx::Canvas::FORCE_LTR_DIRECTIONALITY; @@ -584,7 +584,7 @@ TEST_F(LabelTest, DrawMultiLineString) { label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags); EXPECT_EQ(label.text(), paint_text); EXPECT_EQ(border.left() + extra.width() / 2, text_bounds.x()); - EXPECT_EQ(border.top(), text_bounds.y()); + EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y()); EXPECT_EQ(center_bounds.width(), text_bounds.width()); EXPECT_EQ(center_bounds.height(), text_bounds.height()); expected_flags = gfx::Canvas::MULTI_LINE | @@ -601,7 +601,7 @@ TEST_F(LabelTest, DrawMultiLineString) { label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags); EXPECT_EQ(label.text(), paint_text); EXPECT_EQ(border.left(), text_bounds.x()); - EXPECT_EQ(border.top(), text_bounds.y()); + EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y()); EXPECT_EQ(center_bounds.width(), text_bounds.width()); EXPECT_EQ(center_bounds.height(), text_bounds.height()); expected_flags = gfx::Canvas::MULTI_LINE | @@ -618,7 +618,7 @@ TEST_F(LabelTest, DrawMultiLineString) { label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags); EXPECT_EQ(label.text(), paint_text); EXPECT_EQ(extra.width() + border.left(), text_bounds.x()); - EXPECT_EQ(border.top(), text_bounds.y()); + EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y()); EXPECT_EQ(center_bounds.width(), text_bounds.width()); EXPECT_EQ(center_bounds.height(), text_bounds.height()); expected_flags = gfx::Canvas::MULTI_LINE | @@ -785,9 +785,9 @@ TEST_F(LabelTest, DrawMultiLineStringInRTL) { label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags); EXPECT_EQ(label.text(), paint_text); EXPECT_EQ(extra.width() / 2, text_bounds.x()); - EXPECT_EQ(0, text_bounds.y()); + EXPECT_EQ(extra.height() / 2, text_bounds.y()); EXPECT_GT(text_bounds.width(), kMinTextDimension); - EXPECT_EQ(text_bounds.height(), label.height()); + EXPECT_GT(text_bounds.height(), kMinTextDimension); EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags); EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_CENTER & flags); #if !defined(OS_WIN) @@ -801,9 +801,9 @@ TEST_F(LabelTest, DrawMultiLineStringInRTL) { label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags); EXPECT_EQ(label.text(), paint_text); EXPECT_EQ(extra.width(), text_bounds.x()); - EXPECT_EQ(0, text_bounds.y()); + EXPECT_EQ(extra.height() / 2, text_bounds.y()); EXPECT_GT(text_bounds.width(), kMinTextDimension); - EXPECT_EQ(text_bounds.height(), label.height()); + EXPECT_GT(text_bounds.height(), kMinTextDimension); EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags); EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_RIGHT & flags); #if !defined(OS_WIN) @@ -816,9 +816,9 @@ TEST_F(LabelTest, DrawMultiLineStringInRTL) { label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags); EXPECT_EQ(label.text(), paint_text); EXPECT_EQ(0, text_bounds.x()); - EXPECT_EQ(0, text_bounds.y()); + EXPECT_EQ(extra.height() / 2, text_bounds.y()); EXPECT_GT(text_bounds.width(), kMinTextDimension); - EXPECT_EQ(text_bounds.height(), label.height()); + EXPECT_GT(text_bounds.height(), kMinTextDimension); EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags); EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_LEFT & flags); #if !defined(OS_WIN) @@ -840,9 +840,9 @@ TEST_F(LabelTest, DrawMultiLineStringInRTL) { label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags); EXPECT_EQ(label.text(), paint_text); EXPECT_EQ(border.left() + extra.width() / 2, text_bounds.x()); - EXPECT_EQ(border.top(), text_bounds.y()); + EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y()); EXPECT_EQ(center_bounds.width(), text_bounds.width()); - EXPECT_EQ(label.GetContentsBounds().height(), text_bounds.height()); + EXPECT_EQ(center_bounds.height(), text_bounds.height()); EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags); EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_CENTER & flags); #if !defined(OS_WIN) @@ -855,9 +855,9 @@ TEST_F(LabelTest, DrawMultiLineStringInRTL) { label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags); EXPECT_EQ(label.text(), paint_text); EXPECT_EQ(border.left() + extra.width(), text_bounds.x()); - EXPECT_EQ(border.top(), text_bounds.y()); + EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y()); EXPECT_EQ(center_bounds.width(), text_bounds.width()); - EXPECT_EQ(label.GetContentsBounds().height(), text_bounds.height()); + EXPECT_EQ(center_bounds.height(), text_bounds.height()); EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags); EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_RIGHT & flags); #if !defined(OS_WIN) @@ -870,9 +870,9 @@ TEST_F(LabelTest, DrawMultiLineStringInRTL) { label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags); EXPECT_EQ(label.text(), paint_text); EXPECT_EQ(border.left(), text_bounds.x()); - EXPECT_EQ(border.top(), text_bounds.y()); + EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y()); EXPECT_EQ(center_bounds.width(), text_bounds.width()); - EXPECT_EQ(label.GetContentsBounds().height(), text_bounds.height()); + EXPECT_EQ(center_bounds.height(), text_bounds.height()); EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags); EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_LEFT & flags); #if !defined(OS_WIN) diff --git a/ui/views/views.gyp b/ui/views/views.gyp index 013d4790c8119..f2103c9ce1057 100644 --- a/ui/views/views.gyp +++ b/ui/views/views.gyp @@ -4,6 +4,7 @@ { 'variables': { 'chromium_code': 1, + 'external_ozone_views_files': [], # Sources lists shared with GN build. 'views_sources': [ 'accessibility/native_view_accessibility.cc', @@ -658,6 +659,9 @@ 'msvs_disabled_warnings': [ 4267, ], }], ['use_ozone==1', { + 'sources': [ + '<@(external_ozone_views_files)', + ], 'dependencies': [ '../ozone/ozone.gyp:ozone', ], diff --git a/ui/views/views_delegate.cc b/ui/views/views_delegate.cc index c1c7ca6bd44a0..768d57bb131ed 100644 --- a/ui/views/views_delegate.cc +++ b/ui/views/views_delegate.cc @@ -9,7 +9,8 @@ namespace views { ViewsDelegate::ViewsDelegate() - : views_tsc_factory_(new ViewsTouchSelectionControllerFactory) { + : views_tsc_factory_(new ViewsTouchSelectionControllerFactory), + should_show_titlebar_(true) { ui::TouchSelectionControllerFactory::SetInstance(views_tsc_factory_.get()); } @@ -94,4 +95,12 @@ int ViewsDelegate::GetAppbarAutohideEdges(HMONITOR monitor, } #endif +void ViewsDelegate::SetShouldShowTitleBar(bool show_title_bar) { + should_show_titlebar_ = show_title_bar; +} + +bool ViewsDelegate::ShouldShowTitleBar() const { + return should_show_titlebar_; +} + } // namespace views diff --git a/ui/views/views_delegate.h b/ui/views/views_delegate.h index 0175c8ba20140..7d4480a66ce8e 100644 --- a/ui/views/views_delegate.h +++ b/ui/views/views_delegate.h @@ -149,9 +149,15 @@ class VIEWS_EXPORT ViewsDelegate { // The active ViewsDelegate used by the views system. static ViewsDelegate* views_delegate; + virtual void SetShouldShowTitleBar(bool show_title_bar); + virtual bool ShouldShowTitleBar() const; + private: scoped_ptr views_tsc_factory_; + // Set to true if the window should have the title bar. + bool should_show_titlebar_; + DISALLOW_COPY_AND_ASSIGN(ViewsDelegate); }; diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc index 445967fec218c..97487d3efba6e 100644 --- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc +++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc @@ -659,6 +659,7 @@ void DesktopNativeWidgetAura::GetWindowPlacement( bool DesktopNativeWidgetAura::SetWindowTitle(const base::string16& title) { if (!content_window_) return false; + content_window_->SetTitle(title); return desktop_window_tree_host_->SetWindowTitle(title); } diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc index 3c992813568aa..fcaa027924771 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc @@ -1102,7 +1102,9 @@ void DesktopWindowTreeHostX11::InitX11Window( // program to kill if the window hangs. // XChangeProperty() expects "pid" to be long. COMPILE_ASSERT(sizeof(long) >= sizeof(pid_t), pid_t_bigger_than_long); - long pid = getpid(); + long pid = params.net_wm_pid; + if (!pid) + pid = getpid(); XChangeProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("_NET_WM_PID"), diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc index eecbc23cec0d0..4a4f8ee77fb67 100644 --- a/ui/views/widget/widget.cc +++ b/ui/views/widget/widget.cc @@ -113,7 +113,8 @@ Widget::InitParams::InitParams() desktop_window_tree_host(NULL), layer_type(aura::WINDOW_LAYER_TEXTURED), context(NULL), - force_show_in_taskbar(false) { + force_show_in_taskbar(false), + net_wm_pid(0) { } Widget::InitParams::InitParams(Type type) @@ -136,7 +137,8 @@ Widget::InitParams::InitParams(Type type) desktop_window_tree_host(NULL), layer_type(aura::WINDOW_LAYER_TEXTURED), context(NULL), - force_show_in_taskbar(false) { + force_show_in_taskbar(false), + net_wm_pid(0) { } Widget::InitParams::~InitParams() { diff --git a/ui/views/widget/widget.h b/ui/views/widget/widget.h index ac3e3309bb8a9..dcb08a029f7e2 100644 --- a/ui/views/widget/widget.h +++ b/ui/views/widget/widget.h @@ -268,6 +268,9 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, std::string wm_role_name; std::string wm_class_name; std::string wm_class_class; + // Only used by X11, for root level windows. Specifies the PID set in + // _NET_WM_PID window property. + long net_wm_pid; }; Widget(); diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc index fe562a7c904c9..08e337f7ac4cf 100644 --- a/ui/views/win/hwnd_message_handler.cc +++ b/ui/views/win/hwnd_message_handler.cc @@ -871,8 +871,7 @@ void HWNDMessageHandler::SetFullscreen(bool fullscreen) { void HWNDMessageHandler::SizeConstraintsChanged() { LONG style = GetWindowLong(hwnd(), GWL_STYLE); // Ignore if this is not a standard window. - // WS_OVERLAPPED is just the *absence* of WS_POPUP and WS_CHILD. - if ((style & (WS_POPUP | WS_CHILD)) == WS_OVERLAPPED) + if (!(style & WS_OVERLAPPED)) return; if (delegate_->CanResize()) { diff --git a/ui/views/window/custom_frame_view.cc b/ui/views/window/custom_frame_view.cc index dcc3e69be8818..ca1a523b1aadb 100644 --- a/ui/views/window/custom_frame_view.cc +++ b/ui/views/window/custom_frame_view.cc @@ -334,8 +334,9 @@ bool CustomFrameView::ShouldShowTitleBarAndBorder() const { return false; if (ViewsDelegate::views_delegate) { - return !ViewsDelegate::views_delegate->WindowManagerProvidesTitleBar( - frame_->IsMaximized()); + return ViewsDelegate::views_delegate->ShouldShowTitleBar() && + !ViewsDelegate::views_delegate->WindowManagerProvidesTitleBar( + frame_->IsMaximized()); } return true;