diff --git a/DEPS b/DEPS index f6fb4852..32714fc4 100644 --- a/DEPS +++ b/DEPS
@@ -44,7 +44,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '98d735069d0937f367852ed968a33210ceb527c2', + 'v8_revision': '2e896f6f6039add01a0d1d5efe6d5efe942c38a1', # 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. @@ -60,7 +60,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': '2ed3149ac7f92d367b9629da29c45ffc0d6055d3', + 'swiftshader_revision': '400667e6604eb07e53a2894ede1f492fc3c0b117', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other.
diff --git a/WATCHLISTS b/WATCHLISTS index d24d032..8f92d7d 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -1716,7 +1716,6 @@ 'blink_frames': ['blink-reviews-frames@chromium.org'], 'blink_geolocation': ['mcasas+geolocation@chromium.org', 'mlamouri+watch-blink@chromium.org', - 'mvanouwerkerk+watch@chromium.org', 'timvolodine@chromium.org'], 'blink_heap': ['ager@chromium.org', 'haraken@chromium.org', @@ -1818,8 +1817,7 @@ 'fs@opera.com', 'glenn@chromium.org', 'silviapf@chromium.org'], - 'blink_vibration': ['mlamouri+watch-blink@chromium.org', - 'mvanouwerkerk+watch@chromium.org'], + 'blink_vibration': ['mlamouri+watch-blink@chromium.org'], 'blink_viewport_interaction': ['kenneth.christiansen@gmail.com'], 'blink_w3ctests': ['blink-reviews-w3ctests@chromium.org'], 'blink_web': ['kinuko+watch@chromium.org'],
diff --git a/base/sync_socket.h b/base/sync_socket.h index fcf41550..53fbeb6 100644 --- a/base/sync_socket.h +++ b/base/sync_socket.h
@@ -93,6 +93,9 @@ // processes. Handle handle() const { return handle_; } + // Extracts and takes ownership of the contained handle. + Handle Release(); + protected: Handle handle_;
diff --git a/base/sync_socket_nacl.cc b/base/sync_socket_nacl.cc index 4a02082e..19a20bec 100644 --- a/base/sync_socket_nacl.cc +++ b/base/sync_socket_nacl.cc
@@ -75,6 +75,12 @@ return 0; } +SyncSocket::Handle SyncSocket::Release() { + Handle r = handle_; + handle_ = kInvalidHandle; + return r; +} + CancelableSyncSocket::CancelableSyncSocket() { }
diff --git a/base/sync_socket_posix.cc b/base/sync_socket_posix.cc index 5d9e25e..da995f4b 100644 --- a/base/sync_socket_posix.cc +++ b/base/sync_socket_posix.cc
@@ -207,6 +207,12 @@ return number_chars; } +SyncSocket::Handle SyncSocket::Release() { + Handle r = handle_; + handle_ = kInvalidHandle; + return r; +} + CancelableSyncSocket::CancelableSyncSocket() {} CancelableSyncSocket::CancelableSyncSocket(Handle handle) : SyncSocket(handle) {
diff --git a/base/sync_socket_win.cc b/base/sync_socket_win.cc index c101f77a..797f12f 100644 --- a/base/sync_socket_win.cc +++ b/base/sync_socket_win.cc
@@ -293,6 +293,12 @@ return available; } +SyncSocket::Handle SyncSocket::Release() { + Handle r = handle_; + handle_ = kInvalidHandle; + return r; +} + CancelableSyncSocket::CancelableSyncSocket() : shutdown_event_(base::WaitableEvent::ResetPolicy::MANUAL, base::WaitableEvent::InitialState::NOT_SIGNALED),
diff --git a/base/test/scoped_async_task_scheduler.cc b/base/test/scoped_async_task_scheduler.cc index 397243e..0b5736a 100644 --- a/base/test/scoped_async_task_scheduler.cc +++ b/base/test/scoped_async_task_scheduler.cc
@@ -29,6 +29,9 @@ ScopedAsyncTaskScheduler::~ScopedAsyncTaskScheduler() { DCHECK_EQ(TaskScheduler::GetInstance(), task_scheduler_); + // Without FlushForTesting(), DeleteSoon() and ReleaseSoon() tasks could be + // skipped, resulting in memory leaks. + TaskScheduler::GetInstance()->FlushForTesting(); TaskScheduler::GetInstance()->Shutdown(); TaskScheduler::GetInstance()->JoinForTesting(); TaskScheduler::SetInstance(nullptr);
diff --git a/base/test/scoped_task_environment.cc b/base/test/scoped_task_environment.cc index 8744b4a..b18bf6a 100644 --- a/base/test/scoped_task_environment.cc +++ b/base/test/scoped_task_environment.cc
@@ -32,6 +32,9 @@ RunLoop().RunUntilIdle(); DCHECK_EQ(TaskScheduler::GetInstance(), task_scheduler_); + // Without FlushForTesting(), DeleteSoon() and ReleaseSoon() tasks could be + // skipped, resulting in memory leaks. + TaskScheduler::GetInstance()->FlushForTesting(); TaskScheduler::GetInstance()->Shutdown(); TaskScheduler::GetInstance()->JoinForTesting(); TaskScheduler::SetInstance(nullptr);
diff --git a/build/android/adb_install_apk.py b/build/android/adb_install_apk.py index 7904b41..fd8b8d7 100755 --- a/build/android/adb_install_apk.py +++ b/build/android/adb_install_apk.py
@@ -113,7 +113,8 @@ device.Install(apk, reinstall=args.keep_data, allow_downgrade=args.downgrade, timeout=args.timeout) - except device_errors.CommandFailedError: + except (device_errors.CommandFailedError, + device_errors.DeviceUnreachableError): logging.exception('Failed to install %s', args.apk_name) if blacklist: blacklist.Extend([str(device)], reason='install_failure') @@ -129,4 +130,3 @@ if __name__ == '__main__': sys.exit(main()) -
diff --git a/build/android/provision_devices.py b/build/android/provision_devices.py index 1e8ed92b..ecf22c9 100755 --- a/build/android/provision_devices.py +++ b/build/android/provision_devices.py
@@ -137,7 +137,8 @@ if blacklist: blacklist.Extend([str(device)], reason='provision_timeout') - except device_errors.CommandFailedError: + except (device_errors.CommandFailedError, + device_errors.DeviceUnreachableError): logging.exception('Failed to provision device %s. Adding to blacklist.', str(device)) if blacklist:
diff --git a/build/android/pylib/local/device/local_device_gtest_run.py b/build/android/pylib/local/device/local_device_gtest_run.py index dca9615d..84a37fc1 100644 --- a/build/android/pylib/local/device/local_device_gtest_run.py +++ b/build/android/pylib/local/device/local_device_gtest_run.py
@@ -172,6 +172,8 @@ logging.exception('gtest shard failed.') except device_errors.CommandTimeoutError: logging.exception('gtest shard timed out.') + except device_errors.DeviceUnreachableError: + logging.exception('gtest shard device unreachable.') except Exception: device.ForceStop(self._package) raise
diff --git a/build/android/pylib/local/device/local_device_perf_test_run.py b/build/android/pylib/local/device/local_device_perf_test_run.py index 7e4538d..2ac8b0f 100644 --- a/build/android/pylib/local/device/local_device_perf_test_run.py +++ b/build/android/pylib/local/device/local_device_perf_test_run.py
@@ -245,7 +245,8 @@ result_type = self._RunSingleTest(test) except device_errors.CommandTimeoutError: result_type = base_test_result.ResultType.TIMEOUT - except device_errors.CommandFailedError: + except (device_errors.CommandFailedError, + device_errors.DeviceUnreachableError): logging.exception('Exception when executing %s.', test) result_type = base_test_result.ResultType.FAIL finally:
diff --git a/build/android/tombstones.py b/build/android/tombstones.py index 9838acc..dbc6281c 100755 --- a/build/android/tombstones.py +++ b/build/android/tombstones.py
@@ -49,6 +49,8 @@ datetime.datetime.fromtimestamp(entry['st_mtime'])) except device_errors.CommandFailedError: logging.exception('Could not retrieve tombstones.') + except device_errors.DeviceUnreachableError: + logging.exception('Device unreachable retrieving tombstones.') except device_errors.CommandTimeoutError: logging.exception('Timed out retrieving tombstones.')
diff --git a/cc/tiles/gpu_image_decode_cache_unittest.cc b/cc/tiles/gpu_image_decode_cache_unittest.cc index 437fe706..6be5cca 100644 --- a/cc/tiles/gpu_image_decode_cache_unittest.cc +++ b/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -117,7 +117,13 @@ cache.UnrefImage(another_draw_image); } -TEST(GpuImageDecodeCacheTest, GetTaskForImageLowerQuality) { +// crbug.com/697171. +#if defined(MEMORY_SANITIZER) +#define MAYBE_GetTaskForImageLowerQuality DISABLED_GetTaskForImageLowerQuality +#else +#define MAYBE_GetTaskForImageLowerQuality GetTaskForImageLowerQuality +#endif +TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageLowerQuality) { auto context_provider = TestContextProvider::Create(); context_provider->BindToCurrentThread(); TestGpuImageDecodeCache cache(context_provider.get()); @@ -149,7 +155,14 @@ cache.UnrefImage(another_draw_image); } -TEST(GpuImageDecodeCacheTest, GetTaskForImageDifferentImage) { +// crbug.com/697171. +#if defined(MEMORY_SANITIZER) +#define MAYBE_GetTaskForImageDifferentImage \ + DISABLED_GetTaskForImageDifferentImage +#else +#define MAYBE_GetTaskForImageDifferentImage GetTaskForImageDifferentImage +#endif +TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageDifferentImage) { auto context_provider = TestContextProvider::Create(); context_provider->BindToCurrentThread(); TestGpuImageDecodeCache cache(context_provider.get()); @@ -189,7 +202,13 @@ cache.UnrefImage(second_draw_image); } -TEST(GpuImageDecodeCacheTest, GetTaskForImageLargerScale) { +// crbug.com/697171. +#if defined(MEMORY_SANITIZER) +#define MAYBE_GetTaskForImageLargerScale DISABLED_GetTaskForImageLargerScale +#else +#define MAYBE_GetTaskForImageLargerScale GetTaskForImageLargerScale +#endif +TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageLargerScale) { auto context_provider = TestContextProvider::Create(); context_provider->BindToCurrentThread(); TestGpuImageDecodeCache cache(context_provider.get()); @@ -240,7 +259,15 @@ cache.UnrefImage(third_draw_image); } -TEST(GpuImageDecodeCacheTest, GetTaskForImageLargerScaleNoReuse) { +// crbug.com/697171. +#if defined(MEMORY_SANITIZER) +#define MAYBE_GetTaskForImageLargerScaleNoReuse \ + DISABLED_GetTaskForImageLargerScaleNoReuse +#else +#define MAYBE_GetTaskForImageLargerScaleNoReuse \ + GetTaskForImageLargerScaleNoReuse +#endif +TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageLargerScaleNoReuse) { auto context_provider = TestContextProvider::Create(); context_provider->BindToCurrentThread(); TestGpuImageDecodeCache cache(context_provider.get()); @@ -289,7 +316,13 @@ cache.UnrefImage(third_draw_image); } -TEST(GpuImageDecodeCacheTest, GetTaskForImageHigherQuality) { +// crbug.com/697171. +#if defined(MEMORY_SANITIZER) +#define MAYBE_GetTaskForImageHigherQuality DISABLED_GetTaskForImageHigherQuality +#else +#define MAYBE_GetTaskForImageHigherQuality GetTaskForImageHigherQuality +#endif +TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageHigherQuality) { auto context_provider = TestContextProvider::Create(); context_provider->BindToCurrentThread(); TestGpuImageDecodeCache cache(context_provider.get()); @@ -327,7 +360,15 @@ cache.UnrefImage(second_draw_image); } -TEST(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedAndLocked) { +// crbug.com/697171. +#if defined(MEMORY_SANITIZER) +#define MAYBE_GetTaskForImageAlreadyDecodedAndLocked \ + DISABLED_GetTaskForImageAlreadyDecodedAndLocked +#else +#define MAYBE_GetTaskForImageAlreadyDecodedAndLocked \ + GetTaskForImageAlreadyDecodedAndLocked +#endif +TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageAlreadyDecodedAndLocked) { auto context_provider = TestContextProvider::Create(); context_provider->BindToCurrentThread(); TestGpuImageDecodeCache cache(context_provider.get()); @@ -373,7 +414,15 @@ cache.UnrefImage(draw_image); } -TEST(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedNotLocked) { +// crbug.com/697171. +#if defined(MEMORY_SANITIZER) +#define MAYBE_GetTaskForImageAlreadyDecodedNotLocked \ + DISABLED_GetTaskForImageAlreadyDecodedNotLocked +#else +#define MAYBE_GetTaskForImageAlreadyDecodedNotLocked \ + GetTaskForImageAlreadyDecodedNotLocked +#endif +TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageAlreadyDecodedNotLocked) { auto context_provider = TestContextProvider::Create(); context_provider->BindToCurrentThread(); TestGpuImageDecodeCache cache(context_provider.get()); @@ -419,7 +468,14 @@ cache.UnrefImage(draw_image); } -TEST(GpuImageDecodeCacheTest, GetTaskForImageAlreadyUploaded) { +// crbug.com/697171. +#if defined(MEMORY_SANITIZER) +#define MAYBE_GetTaskForImageAlreadyUploaded \ + DISABLED_GetTaskForImageAlreadyUploaded +#else +#define MAYBE_GetTaskForImageAlreadyUploaded GetTaskForImageAlreadyUploaded +#endif +TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageAlreadyUploaded) { auto context_provider = TestContextProvider::Create(); context_provider->BindToCurrentThread(); TestGpuImageDecodeCache cache(context_provider.get()); @@ -503,7 +559,16 @@ cache.UnrefImage(draw_image); } -TEST(GpuImageDecodeCacheTest, GetTaskForImageCanceledWhileReffedGetsNewTask) { +// crbug.com/697171. +#if defined(MEMORY_SANITIZER) +#define MAYBE_GetTaskForImageCanceledWhileReffedGetsNewTask \ + DISABLED_GetTaskForImageCanceledWhileReffedGetsNewTask +#else +#define MAYBE_GetTaskForImageCanceledWhileReffedGetsNewTask \ + GetTaskForImageCanceledWhileReffedGetsNewTask +#endif +TEST(GpuImageDecodeCacheTest, + MAYBE_GetTaskForImageCanceledWhileReffedGetsNewTask) { auto context_provider = TestContextProvider::Create(); context_provider->BindToCurrentThread(); TestGpuImageDecodeCache cache(context_provider.get()); @@ -555,7 +620,15 @@ cache.UnrefImage(draw_image); } -TEST(GpuImageDecodeCacheTest, NoTaskForImageAlreadyFailedDecoding) { +// crbug.com/697171. +#if defined(MEMORY_SANITIZER) +#define MAYBE_NoTaskForImageAlreadyFailedDecoding \ + DISABLED_NoTaskForImageAlreadyFailedDecoding +#else +#define MAYBE_NoTaskForImageAlreadyFailedDecoding \ + NoTaskForImageAlreadyFailedDecoding +#endif +TEST(GpuImageDecodeCacheTest, MAYBE_NoTaskForImageAlreadyFailedDecoding) { auto context_provider = TestContextProvider::Create(); context_provider->BindToCurrentThread(); TestGpuImageDecodeCache cache(context_provider.get()); @@ -589,7 +662,13 @@ cache.UnrefImage(draw_image); } -TEST(GpuImageDecodeCacheTest, GetDecodedImageForDraw) { +// crbug.com/697171. +#if defined(MEMORY_SANITIZER) +#define MAYBE_GetDecodedImageForDraw DISABLED_GetDecodedImageForDraw +#else +#define MAYBE_GetDecodedImageForDraw GetDecodedImageForDraw +#endif +TEST(GpuImageDecodeCacheTest, MAYBE_GetDecodedImageForDraw) { auto context_provider = TestContextProvider::Create(); context_provider->BindToCurrentThread(); TestGpuImageDecodeCache cache(context_provider.get()); @@ -694,7 +773,15 @@ cache.DrawWithImageFinished(draw_image, decoded_draw_image); } -TEST(GpuImageDecodeCacheTest, GetDecodedImageForDrawLargerScale) { +// crbug.com/697171. +#if defined(MEMORY_SANITIZER) +#define MAYBE_GetDecodedImageForDrawLargerScale \ + DISABLED_GetDecodedImageForDrawLargerScale +#else +#define MAYBE_GetDecodedImageForDrawLargerScale \ + GetDecodedImageForDrawLargerScale +#endif +TEST(GpuImageDecodeCacheTest, MAYBE_GetDecodedImageForDrawLargerScale) { auto context_provider = TestContextProvider::Create(); context_provider->BindToCurrentThread(); TestGpuImageDecodeCache cache(context_provider.get()); @@ -753,7 +840,15 @@ cache.UnrefImage(larger_draw_image); } -TEST(GpuImageDecodeCacheTest, GetDecodedImageForDrawHigherQuality) { +// crbug.com/697171. +#if defined(MEMORY_SANITIZER) +#define MAYBE_GetDecodedImageForDrawHigherQuality \ + DISABLED_GetDecodedImageForDrawHigherQuality +#else +#define MAYBE_GetDecodedImageForDrawHigherQuality \ + GetDecodedImageForDrawHigherQuality +#endif +TEST(GpuImageDecodeCacheTest, MAYBE_GetDecodedImageForDrawHigherQuality) { auto context_provider = TestContextProvider::Create(); context_provider->BindToCurrentThread(); TestGpuImageDecodeCache cache(context_provider.get()); @@ -810,7 +905,14 @@ cache.UnrefImage(higher_quality_draw_image); } -TEST(GpuImageDecodeCacheTest, GetDecodedImageForDrawNegative) { +// crbug.com/697171. +#if defined(MEMORY_SANITIZER) +#define MAYBE_GetDecodedImageForDrawNegative \ + DISABLED_GetDecodedImageForDrawNegative +#else +#define MAYBE_GetDecodedImageForDrawNegative GetDecodedImageForDrawNegative +#endif +TEST(GpuImageDecodeCacheTest, MAYBE_GetDecodedImageForDrawNegative) { auto context_provider = TestContextProvider::Create(); context_provider->BindToCurrentThread(); TestGpuImageDecodeCache cache(context_provider.get()); @@ -847,7 +949,15 @@ cache.UnrefImage(draw_image); } -TEST(GpuImageDecodeCacheTest, GetLargeScaledDecodedImageForDraw) { +// crbug.com/697171. +#if defined(MEMORY_SANITIZER) +#define MAYBE_GetLargeScaledDecodedImageForDraw \ + DISABLED_GetLargeScaledDecodedImageForDraw +#else +#define MAYBE_GetLargeScaledDecodedImageForDraw \ + GetLargeScaledDecodedImageForDraw +#endif +TEST(GpuImageDecodeCacheTest, MAYBE_GetLargeScaledDecodedImageForDraw) { auto context_provider = TestContextProvider::Create(); context_provider->BindToCurrentThread(); TestGpuImageDecodeCache cache(context_provider.get()); @@ -886,7 +996,15 @@ EXPECT_FALSE(cache.DiscardableIsLockedForTesting(draw_image)); } -TEST(GpuImageDecodeCacheTest, AtRasterUsedDirectlyIfSpaceAllows) { +// crbug.com/697171. +#if defined(MEMORY_SANITIZER) +#define MAYBE_AtRasterUsedDirectlyIfSpaceAllows \ + DISABLED_AtRasterUsedDirectlyIfSpaceAllows +#else +#define MAYBE_AtRasterUsedDirectlyIfSpaceAllows \ + AtRasterUsedDirectlyIfSpaceAllows +#endif +TEST(GpuImageDecodeCacheTest, MAYBE_AtRasterUsedDirectlyIfSpaceAllows) { auto context_provider = TestContextProvider::Create(); context_provider->BindToCurrentThread(); TestGpuImageDecodeCache cache(context_provider.get()); @@ -931,8 +1049,16 @@ cache.UnrefImage(draw_image); } +// crbug.com/697171. +#if defined(MEMORY_SANITIZER) +#define MAYBE_GetDecodedImageForDrawAtRasterDecodeMultipleTimes \ + DISABLED_GetDecodedImageForDrawAtRasterDecodeMultipleTimes +#else +#define MAYBE_GetDecodedImageForDrawAtRasterDecodeMultipleTimes \ + GetDecodedImageForDrawAtRasterDecodeMultipleTimes +#endif TEST(GpuImageDecodeCacheTest, - GetDecodedImageForDrawAtRasterDecodeMultipleTimes) { + MAYBE_GetDecodedImageForDrawAtRasterDecodeMultipleTimes) { auto context_provider = TestContextProvider::Create(); context_provider->BindToCurrentThread(); TestGpuImageDecodeCache cache(context_provider.get()); @@ -1091,7 +1217,14 @@ EXPECT_EQ(0u, cache.GetBytesUsedForTesting()); } -TEST(GpuImageDecodeCacheTest, ShouldAggressivelyFreeResources) { +// crbug.com/697171. +#if defined(MEMORY_SANITIZER) +#define MAYBE_ShouldAggressivelyFreeResources \ + DISABLED_ShouldAggressivelyFreeResources +#else +#define MAYBE_ShouldAggressivelyFreeResources ShouldAggressivelyFreeResources +#endif +TEST(GpuImageDecodeCacheTest, MAYBE_ShouldAggressivelyFreeResources) { auto context_provider = TestContextProvider::Create(); context_provider->BindToCurrentThread(); TestGpuImageDecodeCache cache(context_provider.get()); @@ -1155,7 +1288,15 @@ } } -TEST(GpuImageDecodeCacheTest, OrphanedImagesFreeOnReachingZeroRefs) { +// crbug.com/697171. +#if defined(MEMORY_SANITIZER) +#define MAYBE_OrphanedImagesFreeOnReachingZeroRefs \ + DISABLED_OrphanedImagesFreeOnReachingZeroRefs +#else +#define MAYBE_OrphanedImagesFreeOnReachingZeroRefs \ + OrphanedImagesFreeOnReachingZeroRefs +#endif +TEST(GpuImageDecodeCacheTest, MAYBE_OrphanedImagesFreeOnReachingZeroRefs) { auto context_provider = TestContextProvider::Create(); context_provider->BindToCurrentThread(); TestGpuImageDecodeCache cache(context_provider.get()); @@ -1212,7 +1353,15 @@ cache.GetDrawImageSizeForTesting(second_draw_image)); } -TEST(GpuImageDecodeCacheTest, OrphanedZeroRefImagesImmediatelyDeleted) { +// crbug.com/697171. +#if defined(MEMORY_SANITIZER) +#define MAYBE_OrphanedZeroRefImagesImmediatelyDeleted \ + DISABLED_OrphanedZeroRefImagesImmediatelyDeleted +#else +#define MAYBE_OrphanedZeroRefImagesImmediatelyDeleted \ + OrphanedZeroRefImagesImmediatelyDeleted +#endif +TEST(GpuImageDecodeCacheTest, MAYBE_OrphanedZeroRefImagesImmediatelyDeleted) { auto context_provider = TestContextProvider::Create(); context_provider->BindToCurrentThread(); TestGpuImageDecodeCache cache(context_provider.get()); @@ -1262,7 +1411,13 @@ cache.GetDrawImageSizeForTesting(second_draw_image)); } -TEST(GpuImageDecodeCacheTest, QualityCappedAtMedium) { +// crbug.com/697171. +#if defined(MEMORY_SANITIZER) +#define MAYBE_QualityCappedAtMedium DISABLED_QualityCappedAtMedium +#else +#define MAYBE_QualityCappedAtMedium QualityCappedAtMedium +#endif +TEST(GpuImageDecodeCacheTest, MAYBE_QualityCappedAtMedium) { auto context_provider = TestContextProvider::Create(); context_provider->BindToCurrentThread(); TestGpuImageDecodeCache cache(context_provider.get());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java b/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java index a4f3297c..6740fdda 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java
@@ -10,6 +10,7 @@ import android.os.Looper; import org.chromium.base.ContextUtils; +import org.chromium.base.VisibleForTesting; import org.chromium.base.annotations.CalledByNative; import org.chromium.chrome.browser.banners.AppDetailsDelegate; import org.chromium.chrome.browser.customtabs.CustomTabsConnection; @@ -52,6 +53,14 @@ public abstract class AppHooks { private static AppHooksImpl sInstance; + /** + * Sets a mocked instance for testing. + */ + @VisibleForTesting + public static void setInstanceForTesting(AppHooksImpl instance) { + sInstance = instance; + } + @CalledByNative public static AppHooks get() { if (sInstance == null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java index a26b021..f8722440 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
@@ -35,7 +35,6 @@ import org.chromium.base.Log; import org.chromium.base.ObserverList; import org.chromium.base.VisibleForTesting; -import org.chromium.base.library_loader.LibraryLoader; import org.chromium.base.library_loader.LibraryProcessType; import org.chromium.base.library_loader.ProcessInitException; import org.chromium.base.metrics.RecordHistogram; @@ -587,7 +586,9 @@ @VisibleForTesting void cancelOffTheRecordDownloads() { - boolean cancelActualDownload = LibraryLoader.isInitialized() + boolean cancelActualDownload = + BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER) + .isStartupSuccessfullyCompleted() && Profile.getLastUsedProfile().hasOffTheRecordProfile(); List<DownloadSharedPreferenceEntry> entries = mDownloadSharedPreferenceHelper.getEntries();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaNotificationManager.java b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaNotificationManager.java index 8aaa7bf..90bf8e8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaNotificationManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaNotificationManager.java
@@ -80,9 +80,15 @@ // Maps the notification ids to their corresponding notification managers. private static SparseArray<MediaNotificationManager> sManagers; + // Overrides N detection. The production code will use |null|, which uses the Android version + // code. Otherwise, |isRunningN()| will return whatever value is set. + @VisibleForTesting + static Boolean sOverrideIsRunningNForTesting; + // Maps the notification ids to their corresponding choices of the service, button receiver and // group name. - private static SparseArray<NotificationOptions> sMapNotificationIdToOptions; + @VisibleForTesting + static SparseArray<NotificationOptions> sMapNotificationIdToOptions; static { sManagers = new SparseArray<MediaNotificationManager>(); @@ -105,18 +111,23 @@ private int mNotificationId; // ListenerService running for the notification. Only non-null when showing. - private ListenerService mService; + @VisibleForTesting + ListenerService mService; private SparseArray<MediaButtonInfo> mActionToButtonInfo; - private ChromeNotificationBuilder mNotificationBuilder; + @VisibleForTesting + ChromeNotificationBuilder mNotificationBuilder; - private Bitmap mDefaultNotificationLargeIcon; + @VisibleForTesting + Bitmap mDefaultNotificationLargeIcon; // |mMediaNotificationInfo| should be not null if and only if the notification is showing. - private MediaNotificationInfo mMediaNotificationInfo; + @VisibleForTesting + MediaNotificationInfo mMediaNotificationInfo; - private MediaSessionCompat mMediaSession; + @VisibleForTesting + MediaSessionCompat mMediaSession; private final MediaSessionCompat.Callback mMediaSessionCallback = new MediaSessionCompat.Callback() { @@ -157,7 +168,8 @@ } }; - private static class NotificationOptions { + @VisibleForTesting + static class NotificationOptions { public Class<?> serviceClass; public Class<?> receiverClass; public String groupName; @@ -175,24 +187,29 @@ * {@code MediaNotificationListener} callbacks. We have to create a separate derived class for * each type of notification since one class corresponds to one instance of the service only. */ - private abstract static class ListenerService extends Service { - private static final String ACTION_PLAY = - "MediaNotificationManager.ListenerService.PLAY"; - private static final String ACTION_PAUSE = - "MediaNotificationManager.ListenerService.PAUSE"; - private static final String ACTION_STOP = - "MediaNotificationManager.ListenerService.STOP"; - private static final String ACTION_SWIPE = - "MediaNotificationManager.ListenerService.SWIPE"; - private static final String ACTION_CANCEL = - "MediaNotificationManager.ListenerService.CANCEL"; - private static final String ACTION_PREVIOUS_TRACK = + @VisibleForTesting + abstract static class ListenerService extends Service { + @VisibleForTesting + static final String ACTION_PLAY = "MediaNotificationManager.ListenerService.PLAY"; + @VisibleForTesting + static final String ACTION_PAUSE = "MediaNotificationManager.ListenerService.PAUSE"; + @VisibleForTesting + static final String ACTION_STOP = "MediaNotificationManager.ListenerService.STOP"; + @VisibleForTesting + static final String ACTION_SWIPE = "MediaNotificationManager.ListenerService.SWIPE"; + @VisibleForTesting + static final String ACTION_CANCEL = "MediaNotificationManager.ListenerService.CANCEL"; + @VisibleForTesting + static final String ACTION_PREVIOUS_TRACK = "MediaNotificationManager.ListenerService.PREVIOUS_TRACK"; - private static final String ACTION_NEXT_TRACK = + @VisibleForTesting + static final String ACTION_NEXT_TRACK = "MediaNotificationManager.ListenerService.NEXT_TRACK"; - private static final String ACTION_SEEK_FORWARD = + @VisibleForTesting + static final String ACTION_SEEK_FORWARD = "MediaNotificationManager.ListenerService.SEEK_FORWARD"; - private static final String ACTION_SEEK_BACKWARD = + @VisibleForTesting + static final String ACTION_SEEK_BACKWARD = "MediaNotificationmanager.ListenerService.SEEK_BACKWARD"; @Override @@ -212,7 +229,7 @@ @Override public int onStartCommand(Intent intent, int flags, int startId) { - if (!processIntent(intent)) stopSelf(); + if (!processIntent(intent)) stopListenerService(); return START_NOT_STICKY; } @@ -220,7 +237,13 @@ @Nullable protected abstract MediaNotificationManager getManager(); - private boolean processIntent(Intent intent) { + @VisibleForTesting + void stopListenerService() { + stopSelf(); + } + + @VisibleForTesting + boolean processIntent(Intent intent) { if (intent == null) return false; MediaNotificationManager manager = getManager(); @@ -238,14 +261,13 @@ return true; } - private void processAction(Intent intent, MediaNotificationManager manager) { + @VisibleForTesting + void processAction(Intent intent, MediaNotificationManager manager) { String action = intent.getAction(); // Before Android L, instead of using the MediaSession callback, the system will fire // ACTION_MEDIA_BUTTON intents which stores the information about the key event. if (Intent.ACTION_MEDIA_BUTTON.equals(action)) { - assert Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP; - KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); if (event == null) return; if (event.getAction() != KeyEvent.ACTION_DOWN) return; @@ -288,7 +310,7 @@ || ACTION_CANCEL.equals(action)) { manager.onStop( MediaNotificationListener.ACTION_SOURCE_MEDIA_NOTIFICATION); - stopSelf(); + stopListenerService(); } else if (ACTION_PLAY.equals(action)) { manager.onPlay(MediaNotificationListener.ACTION_SOURCE_MEDIA_NOTIFICATION); } else if (ACTION_PAUSE.equals(action)) { @@ -551,7 +573,8 @@ && icon.getHeight() >= MINIMAL_MEDIA_IMAGE_SIZE_PX; } - private static MediaNotificationManager getManager(int notificationId) { + @VisibleForTesting + static MediaNotificationManager getManager(int notificationId) { return sManagers.get(notificationId); } @@ -561,12 +584,8 @@ } @VisibleForTesting - static void ensureManagerForTesting(int notificationId) { - MediaNotificationManager manager = sManagers.get(notificationId); - if (manager == null) { - manager = new MediaNotificationManager(notificationId); - sManagers.put(notificationId, manager); - } + static void setManagerForTesting(int notificationId, MediaNotificationManager manager) { + sManagers.put(notificationId, manager); } @VisibleForTesting @@ -588,7 +607,9 @@ } private static boolean isRunningN() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; + return (sOverrideIsRunningNForTesting != null) + ? sOverrideIsRunningNForTesting + : Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; } /** @@ -612,7 +633,8 @@ } } - private MediaNotificationManager(int notificationId) { + @VisibleForTesting + MediaNotificationManager(int notificationId) { mNotificationId = notificationId; mActionToButtonInfo = new SparseArray<>(); @@ -647,7 +669,8 @@ * * @param service the service that was started */ - private void onServiceStarted(ListenerService service) { + @VisibleForTesting + void onServiceStarted(ListenerService service) { if (mService == service) return; mService = service; @@ -657,30 +680,36 @@ /** * Handles the service destruction destruction. */ - private void onServiceDestroyed() { + @VisibleForTesting + void onServiceDestroyed() { mService = null; if (mMediaNotificationInfo != null) clear(mMediaNotificationInfo.id); } - private void onPlay(int actionSource) { + @VisibleForTesting + void onPlay(int actionSource) { if (!mMediaNotificationInfo.isPaused) return; mMediaNotificationInfo.listener.onPlay(actionSource); } - private void onPause(int actionSource) { + @VisibleForTesting + void onPause(int actionSource) { if (mMediaNotificationInfo.isPaused) return; mMediaNotificationInfo.listener.onPause(actionSource); } - private void onStop(int actionSource) { + @VisibleForTesting + void onStop(int actionSource) { mMediaNotificationInfo.listener.onStop(actionSource); } - private void onMediaSessionAction(int action) { + @VisibleForTesting + void onMediaSessionAction(int action) { mMediaNotificationInfo.listener.onMediaSessionAction(action); } - private void showNotification(MediaNotificationInfo mediaNotificationInfo) { + @VisibleForTesting + void showNotification(MediaNotificationInfo mediaNotificationInfo) { if (mediaNotificationInfo.equals(mMediaNotificationInfo)) return; if (mediaNotificationInfo.isPaused && mMediaNotificationInfo != null && mediaNotificationInfo.tabId != mMediaNotificationInfo.tabId) { @@ -700,8 +729,9 @@ updateNotificationBuilder(); AppHooks.get().startForegroundService(createIntent()); } else { - mService.startService(createIntent()); + getContext().startService(createIntent()); } + // TODO(zqzhang): merge this call to the if statement above? updateNotification(); } @@ -756,11 +786,11 @@ return metadataBuilder.build(); } - private void updateNotification() { + @VisibleForTesting + void updateNotification() { if (mService == null) return; if (mMediaNotificationInfo == null) return; - updateMediaSession(); updateNotificationBuilder(); @@ -780,11 +810,15 @@ } } - private void updateNotificationBuilder() { + @VisibleForTesting + void updateNotificationBuilder() { mNotificationBuilder = NotificationBuilderFactory.createChromeNotificationBuilder( true /* preferCompat */, ChannelsInitializer.CHANNEL_ID_MEDIA); setMediaStyleLayoutForNotificationBuilder(mNotificationBuilder); + // TODO(zqzhang): It's weird that setShowWhen() doesn't work on K. Calling setWhen() to + // force removing the time. + mNotificationBuilder.setShowWhen(false).setWhen(0); mNotificationBuilder.setSmallIcon(mMediaNotificationInfo.notificationSmallIcon); mNotificationBuilder.setAutoCancel(false); mNotificationBuilder.setLocalOnly(true); @@ -811,7 +845,8 @@ : NotificationCompat.VISIBILITY_PUBLIC); } - private void updateMediaSession() { + @VisibleForTesting + void updateMediaSession() { if (!mMediaNotificationInfo.supportsPlayPause()) return; if (mMediaSession == null) mMediaSession = createMediaSession(); @@ -900,6 +935,8 @@ private void setMediaStyleLayoutForNotificationBuilder(ChromeNotificationBuilder builder) { setMediaStyleNotificationText(builder); if (!mMediaNotificationInfo.supportsPlayPause()) { + // TODO(zqzhang): this should be wrong. On pre-N, the notification will look bad when + // the large icon is not set. builder.setLargeIcon(null); } else if (mMediaNotificationInfo.notificationLargeIcon != null) { builder.setLargeIcon(mMediaNotificationInfo.notificationLargeIcon); @@ -913,9 +950,6 @@ } builder.setLargeIcon(mDefaultNotificationLargeIcon); } - // TODO(zqzhang): It's weird that setShowWhen() don't work on K. Calling setWhen() to force - // removing the time. - builder.setShowWhen(false).setWhen(0); addNotificationButtons(builder); }
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index 75f33029..e174070 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -1644,6 +1644,12 @@ "junit/src/org/chromium/chrome/browser/media/router/cast/TestUtils.java", "junit/src/org/chromium/chrome/browser/media/ui/MediaImageManagerTest.java", "junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationButtonComputationTest.java", + "junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationTestShadowNotificationManager.java", + "junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationTestShadowResources.java", + "junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerTestBase.java", + "junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerServiceActionsTest.java", + "junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerServiceLifecycleTest.java", + "junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerNotificationTest.java", "junit/src/org/chromium/chrome/browser/metrics/VariationsSessionTest.java", "junit/src/org/chromium/chrome/browser/notifications/ChannelsInitializerTest.java", "junit/src/org/chromium/chrome/browser/notifications/ChannelsUpdaterTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java index bd1b00b1..02b45c9 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java
@@ -96,6 +96,16 @@ } @Override + protected void shutdownService() { + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + DownloadNotificationServiceTest.super.shutdownService(); + } + }); + } + + @Override protected void tearDown() throws Exception { SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences(); SharedPreferences.Editor editor = sharedPrefs.edit(); @@ -402,7 +412,14 @@ DownloadSharedPreferenceHelper.KEY_PENDING_DOWNLOAD_NOTIFICATIONS, notifications); editor.apply(); startNotificationService(); - getService().onTaskRemoved(new Intent()); + + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + getService().onTaskRemoved(new Intent()); + } + }); + assertTrue(getService().isPaused()); assertFalse(sharedPrefs.contains( DownloadSharedPreferenceHelper.KEY_PENDING_DOWNLOAD_NOTIFICATIONS));
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerNotificationTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerNotificationTest.java new file mode 100644 index 0000000..e6090bb --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerNotificationTest.java
@@ -0,0 +1,216 @@ +// Copyright 2017 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.chrome.browser.media.ui; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.app.Notification; +import android.content.Intent; +import android.graphics.Bitmap; +import android.os.Build; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.robolectric.RuntimeEnvironment; +import org.robolectric.Shadows; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowNotification; + +import org.chromium.base.BaseChromiumApplication; +import org.chromium.content_public.common.MediaMetadata; +import org.chromium.testing.local.LocalRobolectricTestRunner; + +/** + * JUnit tests for checking MediaNotificationManager presents correct notification to Android + * NotificationManager. + */ +@RunWith(LocalRobolectricTestRunner.class) +@Config(manifest = Config.NONE, application = BaseChromiumApplication.class, + shadows = MediaNotificationTestShadowResources.class) +public class MediaNotificationManagerNotificationTest extends MediaNotificationManagerTestBase { + @Test + public void updateNotificationBuilderDisplaysCorrectMetadata_PreN_NonEmptyArtistAndAlbum() { + MediaNotificationManager.sOverrideIsRunningNForTesting = false; + + mMediaNotificationInfoBuilder.setMetadata(new MediaMetadata("title", "artist", "album")); + mMediaNotificationInfoBuilder.setOrigin("https://example.com/"); + + MediaNotificationInfo info = mMediaNotificationInfoBuilder.build(); + Notification notification = updateNotificationBuilderAndBuild(info); + + ShadowNotification shadowNotification = Shadows.shadowOf(notification); + + assertEquals("title", shadowNotification.getContentTitle()); + assertEquals("artist - album", shadowNotification.getContentText()); + if (hasNApis()) { + assertEquals("https://example.com/", + notification.extras.getString(Notification.EXTRA_SUB_TEXT)); + } + } + + @Test + public void updateNotificationBuilderDisplaysCorrectMetadata_PreN_EmptyArtistAndAlbum() { + MediaNotificationManager.sOverrideIsRunningNForTesting = false; + + mMediaNotificationInfoBuilder.setMetadata(new MediaMetadata("title", "", "")); + mMediaNotificationInfoBuilder.setOrigin("https://example.com/"); + + MediaNotificationInfo info = mMediaNotificationInfoBuilder.build(); + Notification notification = updateNotificationBuilderAndBuild(info); + + ShadowNotification shadowNotification = Shadows.shadowOf(notification); + + assertEquals(info.metadata.getTitle(), shadowNotification.getContentTitle()); + assertEquals(info.origin, shadowNotification.getContentText()); + if (hasNApis()) { + assertEquals(null, notification.extras.getString(Notification.EXTRA_SUB_TEXT)); + } + } + + @Test + public void updateNotificationBuilderDisplaysCorrectMetadata_AtLeastN_EmptyArtistAndAlbum() { + MediaNotificationManager.sOverrideIsRunningNForTesting = true; + + mMediaNotificationInfoBuilder.setMetadata(new MediaMetadata("title", "", "")); + mMediaNotificationInfoBuilder.setOrigin("https://example.com/"); + + MediaNotificationInfo info = mMediaNotificationInfoBuilder.build(); + Notification notification = updateNotificationBuilderAndBuild(info); + + ShadowNotification shadowNotification = Shadows.shadowOf(notification); + + assertEquals(info.metadata.getTitle(), shadowNotification.getContentTitle()); + assertEquals("", shadowNotification.getContentText()); + if (hasNApis()) { + assertEquals(info.origin, notification.extras.getString(Notification.EXTRA_SUB_TEXT)); + } + } + + @Test + public void updateNotificationBuilderDisplaysCorrectLargeIcon_WithLargeIcon() { + Bitmap largeIcon = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); + mMediaNotificationInfoBuilder.setNotificationLargeIcon(largeIcon); + + MediaNotificationInfo info = mMediaNotificationInfoBuilder.build(); + Notification notification = updateNotificationBuilderAndBuild(info); + + if (hasNApis()) { + assertTrue(largeIcon.sameAs(iconToBitmap( + notification.extras.getParcelable(Notification.EXTRA_LARGE_ICON)))); + } + } + + @Test + public void updateNotificationBuilderDisplaysCorrectLargeIcon_WithoutLargeIcon_AtLeastN() { + mMediaNotificationInfoBuilder.setNotificationLargeIcon(null); + + MediaNotificationInfo info = mMediaNotificationInfoBuilder.build(); + Notification notification = updateNotificationBuilderAndBuild(info); + + if (hasNApis()) { + assertNull(notification.extras.getParcelable(Notification.EXTRA_LARGE_ICON)); + } + assertNull(getManager().mDefaultNotificationLargeIcon); + } + + @Test + public void updateNotificationBuilderDisplaysCorrectLargeIcon_WithoutLargeIcon_PreN() { + MediaNotificationManager.sOverrideIsRunningNForTesting = false; + assertNull(getManager().mDefaultNotificationLargeIcon); + + mMediaNotificationInfoBuilder.setNotificationLargeIcon(null); + + MediaNotificationInfo info = mMediaNotificationInfoBuilder.build(); + Notification notification = updateNotificationBuilderAndBuild(info); + + assertNotNull(getManager().mDefaultNotificationLargeIcon); + if (hasNApis()) { + assertTrue(getManager().mDefaultNotificationLargeIcon.sameAs(iconToBitmap( + notification.extras.getParcelable(Notification.EXTRA_LARGE_ICON)))); + } + } + + @Test + public void updateNotificationBuilderDisplaysCorrectLargeIcon_DontSupportPlayPause() { + Bitmap largeIcon = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); + mMediaNotificationInfoBuilder.setNotificationLargeIcon(largeIcon).setActions(0); + + MediaNotificationInfo info = mMediaNotificationInfoBuilder.build(); + Notification notification = updateNotificationBuilderAndBuild(info); + + if (hasNApis()) { + assertNull(notification.extras.getParcelable(Notification.EXTRA_LARGE_ICON)); + } + } + + @Test + public void updateNotificationBuilderDisplaysCorrectMiscInfo() { + mMediaNotificationInfoBuilder.setNotificationSmallIcon(1 /* resId */) + .setActions(0) + .setContentIntent(new Intent()); + MediaNotificationInfo info = mMediaNotificationInfoBuilder.build(); + Notification notification = updateNotificationBuilderAndBuild(info); + + ShadowNotification shadowNotification = Shadows.shadowOf(notification); + + assertFalse(shadowNotification.isWhenShown()); + assertFalse(shadowNotification.isOngoing()); + if (hasNApis()) { + assertNotNull(notification.getSmallIcon()); + assertFalse((notification.flags & Notification.FLAG_AUTO_CANCEL) != 0); + assertTrue((notification.flags & Notification.FLAG_LOCAL_ONLY) != 0); + assertEquals(NOTIFICATION_GROUP_NAME, notification.getGroup()); + assertTrue(notification.isGroupSummary()); + assertNull(notification.deleteIntent); + assertNotNull(notification.contentIntent); + assertEquals(Notification.VISIBILITY_PRIVATE, notification.visibility); + } + } + + @Test + public void updateNotificationBuilderDisplaysCorrectMiscInfo_SupportsSwipeAway() { + MediaNotificationInfo info = mMediaNotificationInfoBuilder.build(); + Notification notification = updateNotificationBuilderAndBuild(info); + + ShadowNotification shadowNotification = Shadows.shadowOf(notification); + + assertTrue(shadowNotification.isOngoing()); + if (hasNApis()) { + assertNotNull(notification.deleteIntent); + } + } + + @Test + public void updateNotificationBuilderDisplaysCorrectMiscInfo_Private() { + mMediaNotificationInfoBuilder.setPrivate(false); + MediaNotificationInfo info = mMediaNotificationInfoBuilder.build(); + Notification notification = updateNotificationBuilderAndBuild(info); + + if (hasNApis()) { + assertEquals(Notification.VISIBILITY_PUBLIC, notification.visibility); + } + } + + private Notification updateNotificationBuilderAndBuild(MediaNotificationInfo info) { + getManager().mMediaNotificationInfo = info; + + // This is the fake implementation to ensure |mMediaSession| is non-null. + // + // TODO(zqzhang): move around code so that updateNotification() doesn't need a MediaSession. + getManager().updateMediaSession(); + getManager().updateNotificationBuilder(); + + return getManager().mNotificationBuilder.build(); + } + + private boolean hasNApis() { + return RuntimeEnvironment.getApiLevel() >= Build.VERSION_CODES.N; + } +}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerServiceActionsTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerServiceActionsTest.java new file mode 100644 index 0000000..d91e54e --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerServiceActionsTest.java
@@ -0,0 +1,248 @@ +// Copyright 2017 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.chrome.browser.media.ui; + +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; + +import android.content.Intent; +import android.media.AudioManager; +import android.view.KeyEvent; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +import org.chromium.base.BaseChromiumApplication; +import org.chromium.blink.mojom.MediaSessionAction; +import org.chromium.chrome.browser.media.ui.MediaNotificationManager.ListenerService; +import org.chromium.testing.local.LocalRobolectricTestRunner; + +/** + * JUnit tests for checking {@link MediaNotificationManager.ListenerService} handles intent actionss + * correctly. + */ +@RunWith(LocalRobolectricTestRunner.class) +@Config(manifest = Config.NONE, application = BaseChromiumApplication.class, + shadows = {MediaNotificationTestShadowResources.class, + MediaNotificationTestShadowNotificationManager.class}) +public class MediaNotificationManagerServiceActionsTest extends MediaNotificationManagerTestBase { + @Test + public void testProcessIntentWithNoAction() { + setUpServiceAndClearInvocations(); + doNothing().when(getManager()).onServiceStarted(any(ListenerService.class)); + assertTrue(mService.processIntent(new Intent())); + verify(getManager()).onServiceStarted(mService); + } + + @Test + public void testProcessIntentWithAction() { + setUpService(); + doNothing().when(getManager()).onServiceStarted(any(ListenerService.class)); + Intent intentWithAction = new Intent().setAction("foo"); + assertTrue(mService.processIntent(intentWithAction)); + verify(mService).processAction(intentWithAction, getManager()); + } + + @Test + public void testProcessMediaButton_Play() { + setUpService(); + + mService.processAction( + createMediaButtonActionIntent(KeyEvent.KEYCODE_MEDIA_PLAY), getManager()); + verify(getManager()).onPlay(MediaNotificationListener.ACTION_SOURCE_MEDIA_SESSION); + } + + @Test + public void testProcessMediaButton_Pause() { + setUpService(); + + mService.processAction( + createMediaButtonActionIntent(KeyEvent.KEYCODE_MEDIA_PAUSE), getManager()); + verify(getManager()).onPause(MediaNotificationListener.ACTION_SOURCE_MEDIA_SESSION); + } + + @Test + public void testProcessMediaButton_HeadsetHook() { + setUpService(); + + mMediaNotificationInfoBuilder.setPaused(false); + getManager().mMediaNotificationInfo = mMediaNotificationInfoBuilder.build(); + + mService.processAction( + createMediaButtonActionIntent(KeyEvent.KEYCODE_HEADSETHOOK), getManager()); + verify(getManager()).onPause(MediaNotificationListener.ACTION_SOURCE_MEDIA_SESSION); + } + + @Test + public void testProcessMediaButton_PlayPause() { + setUpService(); + + mService.processAction( + createMediaButtonActionIntent(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE), getManager()); + verify(getManager()).onPause(MediaNotificationListener.ACTION_SOURCE_MEDIA_SESSION); + } + + @Test + public void testProcessMediaButton_Previous() { + setUpService(); + + mService.processAction( + createMediaButtonActionIntent(KeyEvent.KEYCODE_MEDIA_PREVIOUS), getManager()); + verify(getManager()).onMediaSessionAction(MediaSessionAction.PREVIOUS_TRACK); + } + + @Test + public void testProcessMediaButton_Next() { + setUpService(); + + mService.processAction( + createMediaButtonActionIntent(KeyEvent.KEYCODE_MEDIA_NEXT), getManager()); + verify(getManager()).onMediaSessionAction(MediaSessionAction.NEXT_TRACK); + } + + @Test + public void testProcessMediaButton_Rewind() { + setUpService(); + + mService.processAction( + createMediaButtonActionIntent(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD), getManager()); + verify(getManager()).onMediaSessionAction(MediaSessionAction.SEEK_FORWARD); + } + + @Test + public void testProcessMediaButton_Backward() { + setUpService(); + + mService.processAction( + createMediaButtonActionIntent(KeyEvent.KEYCODE_MEDIA_REWIND), getManager()); + verify(getManager()).onMediaSessionAction(MediaSessionAction.SEEK_BACKWARD); + } + + @Test + public void testProcessMediaButtonActionWithNoKeyEvent() { + setUpService(); + + clearInvocations(getManager()); + mService.processAction(new Intent(Intent.ACTION_MEDIA_BUTTON), getManager()); + + verifyZeroInteractions(getManager()); + } + + @Test + public void testProcessMediaButtonActionWithWrongTypeKeyEvent() { + setUpService(); + + clearInvocations(getManager()); + mService.processAction( + new Intent(Intent.ACTION_MEDIA_BUTTON) + .putExtra(Intent.EXTRA_KEY_EVENT, + new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PLAY)), + getManager()); + mService.processAction(new Intent(Intent.ACTION_MEDIA_BUTTON) + .putExtra(Intent.EXTRA_KEY_EVENT, + new KeyEvent(KeyEvent.ACTION_MULTIPLE, + KeyEvent.KEYCODE_MEDIA_PLAY)), + getManager()); + + verifyZeroInteractions(getManager()); + } + + @Test + public void testProcessNotificationButtonAction_Stop() { + setUpService(); + + MediaNotificationManager manager = getManager(); + ListenerService service = mService; + + mService.processAction(new Intent(ListenerService.ACTION_STOP), getManager()); + verify(manager).onStop(MediaNotificationListener.ACTION_SOURCE_MEDIA_NOTIFICATION); + verify(service).stopListenerService(); + } + + @Test + public void testProcessNotificationButtonAction_Swipe() { + setUpService(); + + MediaNotificationManager manager = getManager(); + ListenerService service = mService; + + mService.processAction(new Intent(ListenerService.ACTION_SWIPE), getManager()); + verify(manager).onStop(MediaNotificationListener.ACTION_SOURCE_MEDIA_NOTIFICATION); + verify(service).stopListenerService(); + } + + @Test + public void testProcessNotificationButtonAction_Cancel() { + setUpService(); + + MediaNotificationManager manager = getManager(); + ListenerService service = mService; + + mService.processAction(new Intent(ListenerService.ACTION_CANCEL), getManager()); + verify(manager).onStop(MediaNotificationListener.ACTION_SOURCE_MEDIA_NOTIFICATION); + verify(service).stopListenerService(); + } + + @Test + public void testProcessNotificationButtonAction_Play() { + setUpService(); + + mService.processAction(new Intent(ListenerService.ACTION_PLAY), getManager()); + verify(getManager()).onPlay(MediaNotificationListener.ACTION_SOURCE_MEDIA_NOTIFICATION); + } + + @Test + public void testProcessNotificationButtonAction_Pause() { + setUpService(); + + mService.processAction(new Intent(ListenerService.ACTION_PAUSE), getManager()); + verify(getManager()).onPause(MediaNotificationListener.ACTION_SOURCE_MEDIA_NOTIFICATION); + } + + @Test + public void testProcessNotificationButtonAction_Noisy() { + setUpService(); + + mService.processAction(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY), getManager()); + verify(getManager()).onPause(MediaNotificationListener.ACTION_SOURCE_HEADSET_UNPLUG); + } + + @Test + public void testProcessNotificationButtonAction_PreviousTrack() { + setUpService(); + + mService.processAction(new Intent(ListenerService.ACTION_PREVIOUS_TRACK), getManager()); + verify(getManager()).onMediaSessionAction(MediaSessionAction.PREVIOUS_TRACK); + } + + @Test + public void testProcessNotificationButtonAction_NextTrack() { + setUpService(); + + mService.processAction(new Intent(ListenerService.ACTION_NEXT_TRACK), getManager()); + verify(getManager()).onMediaSessionAction(MediaSessionAction.NEXT_TRACK); + } + + @Test + public void testProcessNotificationButtonAction_SeekForward() { + setUpService(); + + mService.processAction(new Intent(ListenerService.ACTION_SEEK_FORWARD), getManager()); + verify(getManager()).onMediaSessionAction(MediaSessionAction.SEEK_FORWARD); + } + + @Test + public void testProcessNotificationButtonAction_SeekBackward() { + setUpService(); + + mService.processAction(new Intent(ListenerService.ACTION_SEEK_BACKWARD), getManager()); + verify(getManager()).onMediaSessionAction(MediaSessionAction.SEEK_BACKWARD); + } +}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerServiceLifecycleTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerServiceLifecycleTest.java new file mode 100644 index 0000000..3bef5c5 --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerServiceLifecycleTest.java
@@ -0,0 +1,253 @@ +// Copyright 2017 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.chrome.browser.media.ui; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyBoolean; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doCallRealMethod; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import android.app.Notification; +import android.content.Intent; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InOrder; +import org.robolectric.annotation.Config; + +import org.chromium.base.BaseChromiumApplication; +import org.chromium.chrome.browser.media.ui.MediaNotificationManager.ListenerService; +import org.chromium.content_public.common.MediaMetadata; +import org.chromium.testing.local.LocalRobolectricTestRunner; + +import java.util.concurrent.TimeoutException; + +/** + * JUnit tests for checking {@link MediaNotificationManager} handles the listener service life cycle + * correctly. + */ +@RunWith(LocalRobolectricTestRunner.class) +@Config(manifest = Config.NONE, application = BaseChromiumApplication.class, + shadows = {MediaNotificationTestShadowResources.class, + MediaNotificationTestShadowNotificationManager.class}) +public class MediaNotificationManagerServiceLifecycleTest extends MediaNotificationManagerTestBase { + @Test + public void testServiceLifeCycle() { + ensureMediaNotificationInfo(); + + Intent intent = getManager().createIntent(); + + assertNull(mService); + mMockContext.startService(intent); + verify(getManager()).onServiceStarted(mService); + assertNotNull(mService); + verify(mService).onStartCommand(intent, 0, 0); + + mService.stopListenerService(); + assertNull(mService); + } + + @Test + public void testProcessIntentFailureStopsService() throws TimeoutException { + MediaNotificationManager manager = getManager(); + setUpService(); + + ListenerService service = mService; + doReturn(false).when(mService).processIntent(any(Intent.class)); + mMockContext.startService(new Intent()); + verify(service).stopListenerService(); + assertNull(getManager()); + verify(manager).onServiceDestroyed(); + } + + @Test + public void testProcessNullIntent() { + setUpService(); + assertFalse(mService.processIntent(null)); + } + + @Test + public void testProcessIntentWhenManagerIsNull() { + setUpService(); + MediaNotificationManager.setManagerForTesting(NOTIFICATION_ID, null); + assertFalse(mService.processIntent(new Intent())); + } + + @Test + public void testProcessIntentWhenNotificationInfoIsNull() { + setUpService(); + getManager().mMediaNotificationInfo = null; + assertFalse(mService.processIntent(new Intent())); + } + + @Test + public void testShowNotificationIsNoOpWhenInfoMatches() { + doCallRealMethod().when(getManager()).onServiceStarted(any(ListenerService.class)); + doNothing().when(getManager()).updateNotification(); + setUpServiceAndClearInvocations(); + + MediaNotificationInfo newInfo = mMediaNotificationInfoBuilder.build(); + getManager().showNotification(newInfo); + + verify(getManager()).showNotification(newInfo); + verifyNoMoreInteractions(getManager()); + verify(mMockAppHooks, never()).startForegroundService(any(Intent.class)); + verify(mMockContext, never()).startService(any(Intent.class)); + } + + @Test + public void testShowNotificationIsNoOpWhenInfoIsPausedAndFromAnotherTab() { + doCallRealMethod().when(getManager()).onServiceStarted(any(ListenerService.class)); + doNothing().when(getManager()).updateNotification(); + mMediaNotificationInfoBuilder.setTabId(0); + setUpServiceAndClearInvocations(); + + mMediaNotificationInfoBuilder.setTabId(1).setPaused(true); + MediaNotificationInfo newInfo = mMediaNotificationInfoBuilder.build(); + getManager().showNotification(newInfo); + + verify(getManager()).showNotification(newInfo); + verifyNoMoreInteractions(getManager()); + verify(mMockAppHooks, never()).startForegroundService(any(Intent.class)); + verify(mMockContext, never()).startService(any(Intent.class)); + } + + @Test + public void testShowNotificationWhenServiceNotCreated() { + MediaNotificationInfo newInfo = mMediaNotificationInfoBuilder.build(); + getManager().showNotification(newInfo); + + verify(getManager(), times(1)).updateMediaSession(); + verify(getManager(), times(1)).updateNotificationBuilder(); + verify(mMockContext, never()).startService(any(Intent.class)); + verify(mMockAppHooks, times(1)).startForegroundService(any(Intent.class)); + verify(getManager(), times(1)).updateNotification(); + } + + @Test + public void testShowNotificationWhenServiceAlreadyCreated() { + doCallRealMethod().when(getManager()).onServiceStarted(any(ListenerService.class)); + doNothing().when(getManager()).updateNotification(); + setUpServiceAndClearInvocations(); + + mMediaNotificationInfoBuilder.setPaused(true); + MediaNotificationInfo newInfo = mMediaNotificationInfoBuilder.build(); + getManager().showNotification(newInfo); + + verify(getManager()).showNotification(newInfo); + verify(mMockAppHooks, never()).startForegroundService(any(Intent.class)); + verify(mMockContext).startService(any(Intent.class)); + } + + @Test + public void testShowNotificationBeforeServiceCreatedUpdatesNotificationInfo() { + doCallRealMethod().when(getManager()).onServiceStarted(any(ListenerService.class)); + doNothing().when(getManager()).updateNotification(); + + // The initial call to |showNotification()| should update the notification info and request + // to start the service. + MediaNotificationInfo oldInfo = mMediaNotificationInfoBuilder.build(); + getManager().showNotification(oldInfo); + + InOrder order = inOrder(getManager(), mMockAppHooks); + + assertEquals(oldInfo, getManager().mMediaNotificationInfo); + order.verify(getManager(), times(1)).updateMediaSession(); + order.verify(getManager(), times(1)).updateNotificationBuilder(); + order.verify(mMockAppHooks, times(1)).startForegroundService(any(Intent.class)); + order.verify(getManager(), times(1)).updateNotification(); + + // The second call to |showNotification()| should only update the notification info. + mMediaNotificationInfoBuilder.setMetadata(new MediaMetadata("new title", "", "")); + MediaNotificationInfo newInfo = mMediaNotificationInfoBuilder.build(); + getManager().showNotification(newInfo); + + assertEquals(newInfo, getManager().mMediaNotificationInfo); + order.verify(getManager(), times(1)).updateMediaSession(); + order.verify(getManager(), times(1)).updateNotificationBuilder(); + order.verify(mMockAppHooks, times(1)).startForegroundService(any(Intent.class)); + order.verify(getManager(), times(1)).updateNotification(); + + verify(getManager(), never()).onServiceStarted(any(ListenerService.class)); + + // Simulate the service has started. + mMockContext.startService(getManager().createIntent()); + order.verify(getManager(), times(1)).onServiceStarted(mService); + order.verify(getManager(), times(1)).updateNotification(); + } + + @Test + public void updateNotificationIsNoOpBeforeServiceCreated() { + getManager().mMediaNotificationInfo = mMediaNotificationInfoBuilder.build(); + getManager().updateNotification(); + + verify(getManager()).updateNotification(); + verify(getManager(), never()).updateMediaSession(); + verify(getManager(), never()).updateNotificationBuilder(); + } + + @Test + public void updateNotificationIsNoOpWhenNotificiationInfoIsNull() { + setUpService(); + getManager().mService = mService; + getManager().mMediaNotificationInfo = null; + getManager().updateNotification(); + + verify(getManager()).updateNotification(); + verify(getManager(), never()).updateMediaSession(); + verify(getManager(), never()).updateNotificationBuilder(); + + verify(mService, never()).stopForeground(anyBoolean()); + verify(mService, never()).startForeground(anyInt(), any(Notification.class)); + } + + @Test + public void updateNotificationSetsServiceBackgroundWhenPausedAndSupportsSwipeAway() { + mMediaNotificationInfoBuilder.setPaused(true); + setUpService(); + getManager().mService = mService; + getManager().mMediaNotificationInfo = mMediaNotificationInfoBuilder.build(); + getManager().updateNotification(); + + verify(mService).stopForeground(false); + // One of the invocations comes from |setUpService()|. + verify(MediaNotificationTestShadowNotificationManager.sMockObserver, times(2)) + .notify(eq(NOTIFICATION_ID), any(Notification.class)); + } + + @Test + public void updateNotificationSetsServiceBackgroundWhenPausedButDoesntSupportSwipeAway() { + mMediaNotificationInfoBuilder.setPaused(true).setActions(0); + setUpService(); + getManager().mService = mService; + getManager().mMediaNotificationInfo = mMediaNotificationInfoBuilder.build(); + getManager().updateNotification(); + + verify(mService).startForeground(eq(NOTIFICATION_ID), any(Notification.class)); + } + + @Test + public void updateNotificationSetsServiceForegroundWhenPlaying() { + mMediaNotificationInfoBuilder.setPaused(false); + setUpService(); + getManager().mService = mService; + getManager().mMediaNotificationInfo = mMediaNotificationInfoBuilder.build(); + getManager().updateNotification(); + + verify(mService).startForeground(eq(NOTIFICATION_ID), any(Notification.class)); + } +}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerTestBase.java b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerTestBase.java new file mode 100644 index 0000000..df9dbee --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerTestBase.java
@@ -0,0 +1,193 @@ +// Copyright 2017 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.chrome.browser.media.ui; + +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Icon; +import android.os.Build; +import android.support.v4.media.session.MediaSessionCompat; +import android.view.KeyEvent; + +import org.junit.Before; + +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.shadows.ShadowLog; + +import org.chromium.base.CommandLine; +import org.chromium.base.ContextUtils; +import org.chromium.chrome.browser.AppHooks; +import org.chromium.chrome.browser.AppHooksImpl; +import org.chromium.chrome.browser.media.ui.MediaNotificationManager.ListenerService; +import org.chromium.content_public.common.MediaMetadata; + +/** + * Common test fixtures for MediaNotificationManager JUnit tests. + */ +public class MediaNotificationManagerTestBase { + static final int NOTIFICATION_ID = 0; + static final String NOTIFICATION_GROUP_NAME = "group-name"; + Context mMockContext; + MockListenerService mService; + MediaNotificationListener mListener; + AppHooksImpl mMockAppHooks; + + MediaNotificationInfo.Builder mMediaNotificationInfoBuilder; + + static class MockMediaNotificationManager extends MediaNotificationManager { + public MockMediaNotificationManager() { + super(NOTIFICATION_ID); + } + } + + static class MockListenerService extends ListenerService { + @Override + protected MediaNotificationManager getManager() { + return MediaNotificationManager.getManager(NOTIFICATION_ID); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + return super.onStartCommand(intent, flags, startId); + } + } + + static class MockMediaButtonReceiver extends MediaButtonReceiver { + @Override + public Class<?> getServiceClass() { + return MockListenerService.class; + } + } + + @Before + public void setUp() { + // For checking the notification presented to NotificationManager. + assertTrue(RuntimeEnvironment.getApiLevel() >= Build.VERSION_CODES.N); + + ShadowLog.stream = System.out; + + mMockContext = spy(RuntimeEnvironment.application); + ContextUtils.initApplicationContextForTests(mMockContext); + + mListener = mock(MediaNotificationListener.class); + + MediaNotificationManager.sMapNotificationIdToOptions.put(NOTIFICATION_ID, + new MediaNotificationManager.NotificationOptions(MockListenerService.class, + MockMediaButtonReceiver.class, NOTIFICATION_GROUP_NAME)); + + MediaNotificationManager.setManagerForTesting( + NOTIFICATION_ID, spy(new MockMediaNotificationManager())); + + mMediaNotificationInfoBuilder = + new MediaNotificationInfo.Builder() + .setMetadata(new MediaMetadata("title", "artist", "album")) + .setOrigin("https://example.com") + .setListener(mListener) + .setId(NOTIFICATION_ID); + + doNothing().when(getManager()).onServiceStarted(any(ListenerService.class)); + // Robolectric does not have "ShadowMediaSession". + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + MediaSessionCompat mockSession = mock(MediaSessionCompat.class); + getManager().mMediaSession = mockSession; + doReturn(null).when(mockSession).getSessionToken(); + return "Created mock media session"; + } + }) + .when(getManager()) + .updateMediaSession(); + + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + Intent intent = (Intent) invocation.getArgument(0); + startService(intent); + return new ComponentName(mMockContext, MockListenerService.class); + } + }) + .when(mMockContext) + .startService(any(Intent.class)); + + mMockAppHooks = mock(AppHooksImpl.class); + AppHooks.setInstanceForTesting(mMockAppHooks); + + // Init the command line to avoid assertion failure in |SysUtils#isLowEndDevice()|. + CommandLine.init(null); + } + + MediaNotificationManager getManager() { + return MediaNotificationManager.getManager(NOTIFICATION_ID); + } + + void ensureMediaNotificationInfo() { + getManager().mMediaNotificationInfo = mMediaNotificationInfoBuilder.build(); + } + + void setUpServiceAndClearInvocations() { + setUpService(); + clearInvocations(getManager()); + clearInvocations(mService); + clearInvocations(mMockContext); + } + + void setUpService() { + ensureMediaNotificationInfo(); + + Intent intent = getManager().createIntent(); + mMockContext.startService(intent); + } + + private void startService(Intent intent) { + ensureService(); + mService.onStartCommand(intent, 0, 0); + } + + private void ensureService() { + if (mService != null) return; + mService = spy(new MockListenerService()); + + doAnswer(new Answer() { + public Object answer(InvocationOnMock invocation) { + mService.onDestroy(); + mService = null; + return "service stopped"; + } + }) + .when(mService) + .stopListenerService(); + } + + Intent createMediaButtonActionIntent(int keyCode) { + Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON); + KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode); + intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); + + return intent; + } + + Bitmap iconToBitmap(Icon icon) { + if (icon == null) return null; + + BitmapDrawable drawable = (BitmapDrawable) icon.loadDrawable(mMockContext); + assert drawable != null; + return drawable.getBitmap(); + } +}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationTestShadowNotificationManager.java b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationTestShadowNotificationManager.java new file mode 100644 index 0000000..d42c637b --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationTestShadowNotificationManager.java
@@ -0,0 +1,33 @@ +// Copyright 2017 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.chrome.browser.media.ui; + +import static org.mockito.Mockito.mock; + +import android.app.Notification; +import android.app.NotificationManager; + +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; +import org.robolectric.shadows.ShadowNotificationManager; + +/** + * Dummy Robolectric shadow for Android NotificationManager for MediaNotification tests. + */ +@Implements(NotificationManager.class) +public class MediaNotificationTestShadowNotificationManager extends ShadowNotificationManager { + public static final NotificationManager sMockObserver; + + static { + sMockObserver = mock(NotificationManager.class); + } + + @Implementation + @Override + public void notify(int id, Notification notification) { + sMockObserver.notify(id, notification); + super.notify(id, notification); + } +}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationTestShadowResources.java b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationTestShadowResources.java new file mode 100644 index 0000000..7febe444 --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationTestShadowResources.java
@@ -0,0 +1,39 @@ +// Copyright 2017 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.chrome.browser.media.ui; + +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +import android.content.res.Resources; + +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; +import org.robolectric.shadows.ShadowResources; + +/** + * Dummy Robolectric shadow for Android Resources for MediaNotification tests. + */ +@Implements(Resources.class) +public class MediaNotificationTestShadowResources extends ShadowResources { + public static final Resources sResources; + + static { + sResources = mock(Resources.class); + doReturn("mocked text").when(sResources).getText(anyInt()); + doReturn("mocked resource name").when(sResources).getResourceName(anyInt()); + } + + @Implementation + public CharSequence getText(int id) { + return sResources.getText(id); + } + + @Implementation + public CharSequence getResourceName(int id) { + return sResources.getResourceName(id); + } +}
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc index 8d60a9f1..0e806fa 100644 --- a/chrome/browser/apps/guest_view/web_view_browsertest.cc +++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -3128,7 +3128,13 @@ TestHelper("testFindAPI", "web_view/shim", NO_TEST_SERVER); } -IN_PROC_BROWSER_TEST_P(WebViewTest, Shim_TestFindAPI_findupdate) { +// crbug.com/697171 +#if defined(MEMORY_SANITIZER) +#define MAYBE_Shim_TestFindAPI_findupdate DISABLED_Shim_TestFindAPI_findupdate +#else +#define MAYBE_Shim_TestFindAPI_findupdate Shim_TestFindAPI_findupdate +#endif +IN_PROC_BROWSER_TEST_P(WebViewTest, MAYBE_Shim_TestFindAPI_findupdate) { TestHelper("testFindAPI_findupdate", "web_view/shim", NO_TEST_SERVER); }
diff --git a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.cc b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.cc index 71f1781..fd2c314b 100644 --- a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.cc +++ b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.cc
@@ -155,6 +155,11 @@ app_manager_->AddObserver(this); pref_change_registrar_.reset(new PrefChangeRegistrar()); pref_change_registrar_->Init(profile_->GetPrefs()); + // Kiosk app can be started only when policy compliance is reported. + pref_change_registrar_->Add( + prefs::kArcPolicyComplianceReported, + base::Bind(&ArcKioskAppService::PreconditionsChanged, + base::Unretained(this))); notification_blocker_.reset(new ArcKioskNotificationBlocker()); PreconditionsChanged(); } @@ -185,9 +190,15 @@ VLOG_IF(2, app_info_ && app_info_->ready) << "Kiosk app is ready"; VLOG(2) << "Maintenance session is " << (maintenance_session_running_ ? "running" : "not running"); + VLOG(2) << "Policy compliance is " + << (profile_->GetPrefs()->GetBoolean( + prefs::kArcPolicyComplianceReported) + ? "reported" + : "not yet reported"); VLOG(2) << "Kiosk app with id: " << app_id_ << " is " << (app_launcher_ ? "already launched" : "not yet launched"); - if (app_info_ && app_info_->ready && !maintenance_session_running_) { + if (app_info_ && app_info_->ready && !maintenance_session_running_ && + profile_->GetPrefs()->GetBoolean(prefs::kArcPolicyComplianceReported)) { if (!app_launcher_) { VLOG(2) << "Starting kiosk app"; app_launcher_ = base::MakeUnique<ArcKioskAppLauncher>(
diff --git a/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc b/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc index f628eb5..e837bbf 100644 --- a/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc +++ b/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc
@@ -311,6 +311,12 @@ arc_bridge_service()->policy()->RemoveObserver(this); } +// static +void ArcPolicyBridge::RegisterProfilePrefs( + user_prefs::PrefRegistrySyncable* registry) { + registry->RegisterBooleanPref(prefs::kArcPolicyComplianceReported, false); +} + void ArcPolicyBridge::OverrideIsManagedForTesting(bool is_managed) { is_managed_ = is_managed; } @@ -392,6 +398,8 @@ std::unique_ptr<base::Value> parsed_json) { // Always returns "compliant". callback.Run(kPolicyCompliantJson); + GetProfile()->GetPrefs()->SetBoolean(prefs::kArcPolicyComplianceReported, + true); const base::DictionaryValue* dict = nullptr; if (parsed_json->GetAsDictionary(&dict))
diff --git a/chrome/browser/chromeos/arc/policy/arc_policy_bridge.h b/chrome/browser/chromeos/arc/policy/arc_policy_bridge.h index 51fa6d7..4966c0a 100644 --- a/chrome/browser/chromeos/arc/policy/arc_policy_bridge.h +++ b/chrome/browser/chromeos/arc/policy/arc_policy_bridge.h
@@ -46,6 +46,8 @@ policy::PolicyService* policy_service); ~ArcPolicyBridge() override; + static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); + void OverrideIsManagedForTesting(bool is_managed); // InstanceHolder<mojom::PolicyInstance>::Observer overrides.
diff --git a/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc b/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc index 19ab2ee..d8639db 100644 --- a/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc +++ b/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc
@@ -12,6 +12,7 @@ #include "chrome/browser/chromeos/arc/policy/arc_policy_bridge.h" #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h" #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h" +#include "chrome/common/pref_names.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile_manager.h" #include "components/arc/arc_bridge_service.h" @@ -143,8 +144,8 @@ testing_profile_manager_ = base::MakeUnique<TestingProfileManager>( TestingBrowserProcess::GetGlobal()); ASSERT_TRUE(testing_profile_manager_->SetUp()); - ASSERT_TRUE( - testing_profile_manager_->CreateTestingProfile("user@gmail.com")); + profile_ = testing_profile_manager_->CreateTestingProfile("user@gmail.com"); + ASSERT_TRUE(profile_); } protected: @@ -152,6 +153,7 @@ FakePolicyInstance* policy_instance() { return policy_instance_.get(); } policy::PolicyMap& policy_map() { return policy_map_; } base::RunLoop& run_loop() { return run_loop_; } + Profile* profile() { return profile_; } private: safe_json::TestingJsonParser::ScopedFactoryOverride factory_override_; @@ -159,6 +161,7 @@ std::unique_ptr<chromeos::ScopedUserManagerEnabler> user_manager_enabler_; std::unique_ptr<TestingProfileManager> testing_profile_manager_; base::RunLoop run_loop_; + TestingProfile* profile_; std::unique_ptr<ArcBridgeService> bridge_service_; std::unique_ptr<ArcPolicyBridge> policy_bridge_; @@ -365,29 +368,43 @@ } TEST_F(ArcPolicyBridgeTest, EmptyReportComplianceTest) { + ASSERT_FALSE( + profile()->GetPrefs()->GetBoolean(prefs::kArcPolicyComplianceReported)); policy_bridge()->ReportCompliance( "{}", PolicyComplianceCallback(run_loop().QuitClosure(), kPolicyCompliantResponse)); run_loop().Run(); + ASSERT_TRUE( + profile()->GetPrefs()->GetBoolean(prefs::kArcPolicyComplianceReported)); } TEST_F(ArcPolicyBridgeTest, ParsableReportComplianceTest) { + ASSERT_FALSE( + profile()->GetPrefs()->GetBoolean(prefs::kArcPolicyComplianceReported)); policy_bridge()->ReportCompliance( "{\"nonComplianceDetails\" : []}", PolicyComplianceCallback(run_loop().QuitClosure(), kPolicyCompliantResponse)); run_loop().Run(); + ASSERT_TRUE( + profile()->GetPrefs()->GetBoolean(prefs::kArcPolicyComplianceReported)); } TEST_F(ArcPolicyBridgeTest, NonParsableReportComplianceTest) { + ASSERT_FALSE( + profile()->GetPrefs()->GetBoolean(prefs::kArcPolicyComplianceReported)); policy_bridge()->ReportCompliance( "\"nonComplianceDetails\" : [}", PolicyComplianceCallback(run_loop().QuitClosure(), kPolicyCompliantResponse)); run_loop().Run(); + ASSERT_FALSE( + profile()->GetPrefs()->GetBoolean(prefs::kArcPolicyComplianceReported)); } TEST_F(ArcPolicyBridgeTest, ReportComplianceTest_WithNonCompliantDetails) { + ASSERT_FALSE( + profile()->GetPrefs()->GetBoolean(prefs::kArcPolicyComplianceReported)); policy_bridge()->ReportCompliance( "{\"nonComplianceDetails\" : " "[{\"fieldPath\":\"\",\"nonComplianceReason\":0,\"packageName\":\"\"," @@ -395,6 +412,8 @@ PolicyComplianceCallback(run_loop().QuitClosure(), kPolicyCompliantResponse)); run_loop().Run(); + ASSERT_TRUE( + profile()->GetPrefs()->GetBoolean(prefs::kArcPolicyComplianceReported)); } // This and the following test send the policies through a mojo connection
diff --git a/chrome/browser/predictors/resource_prefetch_common.cc b/chrome/browser/predictors/resource_prefetch_common.cc index d324969..ebdbea8 100644 --- a/chrome/browser/predictors/resource_prefetch_common.cc +++ b/chrome/browser/predictors/resource_prefetch_common.cc
@@ -25,6 +25,7 @@ const char kPrefetchingMode[] = "prefetching"; const char kEnableUrlLearningParamName[] = "enable-url-learning"; const char kEnableManifestsParamName[] = "enable-manifests"; +const char kEnableOriginLearningParamName[] = "enable-origin-learning"; const base::Feature kSpeculativeResourcePrefetchingFeature = base::Feature(kSpeculativeResourcePrefetchingFeatureName, @@ -71,6 +72,11 @@ if (enable_manifests_value == "true") config->is_manifests_enabled = true; + bool enable_origin_learning = base::GetFieldTrialParamValueByFeature( + kSpeculativeResourcePrefetchingFeature, + kEnableOriginLearningParamName) == "true"; + config->is_origin_learning_enabled = enable_origin_learning; + // Ensure that a resource that was only seen once is never prefetched. This // prevents the easy mistake of trying to prefetch an ephemeral url. DCHECK_GT(config->min_resource_hits_to_trigger_prefetch, 1U); @@ -146,7 +152,7 @@ max_prefetches_inflight_per_host_per_navigation(3), is_url_learning_enabled(false), is_manifests_enabled(false), - is_origin_prediction_enabled(false) {} + is_origin_learning_enabled(false) {} ResourcePrefetchPredictorConfig::ResourcePrefetchPredictorConfig( const ResourcePrefetchPredictorConfig& other) = default;
diff --git a/chrome/browser/predictors/resource_prefetch_common.h b/chrome/browser/predictors/resource_prefetch_common.h index e13e6cc8..c430327 100644 --- a/chrome/browser/predictors/resource_prefetch_common.h +++ b/chrome/browser/predictors/resource_prefetch_common.h
@@ -27,6 +27,7 @@ extern const char kPrefetchingMode[]; extern const char kEnableUrlLearningParamName[]; extern const char kEnableManifestsParamName[]; +extern const char kEnableOriginLearningParamName[]; extern const base::Feature kSpeculativeResourcePrefetchingFeature; struct ResourcePrefetchPredictorConfig; @@ -135,8 +136,8 @@ bool is_url_learning_enabled; // True iff the predictor could use manifests. bool is_manifests_enabled; - // True iff the origin-based prediction is enabled. - bool is_origin_prediction_enabled; + // True iff origin-based learning is enabled. + bool is_origin_learning_enabled; }; } // namespace predictors
diff --git a/chrome/browser/predictors/resource_prefetch_common_unittest.cc b/chrome/browser/predictors/resource_prefetch_common_unittest.cc index 56e1203..643d3d0 100644 --- a/chrome/browser/predictors/resource_prefetch_common_unittest.cc +++ b/chrome/browser/predictors/resource_prefetch_common_unittest.cc
@@ -73,7 +73,7 @@ EXPECT_FALSE(config.IsSmallDBEnabledForTest()); EXPECT_FALSE(config.is_url_learning_enabled); EXPECT_FALSE(config.is_manifests_enabled); - EXPECT_FALSE(config.is_origin_prediction_enabled); + EXPECT_FALSE(config.is_origin_learning_enabled); EXPECT_GT(config.min_resource_hits_to_trigger_prefetch, 1U); } @@ -162,6 +162,19 @@ EXPECT_TRUE(config.is_manifests_enabled); } +TEST_F(ResourcePrefetchCommonTest, EnableOriginLearning) { + variations::testing::VariationParamsManager params_manager( + "dummy-trial", + {{kModeParamName, kLearningMode}, + {kEnableOriginLearningParamName, "true"}}, + {kSpeculativeResourcePrefetchingFeatureName}); + + ResourcePrefetchPredictorConfig config; + EXPECT_TRUE(IsSpeculativeResourcePrefetchingEnabled(profile_.get(), &config)); + TestIsPrefetchLearning(config); + EXPECT_TRUE(config.is_origin_learning_enabled); +} + // Verifies whether prefetching is disabled according to the network type. But // learning should not be disabled by network. TEST_F(ResourcePrefetchCommonTest, RespectsNetworkSettings) {
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.cc b/chrome/browser/predictors/resource_prefetch_predictor.cc index 76719ae..5bc03cb0 100644 --- a/chrome/browser/predictors/resource_prefetch_predictor.cc +++ b/chrome/browser/predictors/resource_prefetch_predictor.cc
@@ -804,7 +804,7 @@ if (!response.is_no_store) page_request_summary.subresource_requests.push_back(response); - if (config_.is_origin_prediction_enabled) + if (config_.is_origin_learning_enabled) UpdateOrAddToOrigins(&page_request_summary.origins, response); } @@ -813,7 +813,7 @@ DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_EQ(INITIALIZED, initialization_state_); - if (!config_.is_origin_prediction_enabled) + if (!config_.is_origin_learning_enabled) return; NavigationMap::const_iterator nav_it = @@ -1228,7 +1228,7 @@ config_.max_hosts_to_track, host_table_cache_.get(), summary.initial_url.host(), host_redirect_table_cache_.get()); - if (config_.is_origin_prediction_enabled) { + if (config_.is_origin_learning_enabled) { LearnOrigins(host, summary.origins, config_.max_hosts_to_track, origin_table_cache_.get()); }
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc index 71ed0e3..a67e7da 100644 --- a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc +++ b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
@@ -241,7 +241,7 @@ config.min_resource_confidence_to_trigger_prefetch = 0.5; config.is_url_learning_enabled = true; config.is_manifests_enabled = true; - config.is_origin_prediction_enabled = true; + config.is_origin_learning_enabled = true; config.mode |= ResourcePrefetchPredictorConfig::LEARNING; predictor_.reset(new ResourcePrefetchPredictor(config, profile_.get()));
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 623c2af..126c287 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -606,6 +606,7 @@ #if defined(OS_CHROMEOS) arc::ArcSessionManager::RegisterProfilePrefs(registry); + arc::ArcPolicyBridge::RegisterProfilePrefs(registry); chromeos::first_run::RegisterProfilePrefs(registry); chromeos::file_system_provider::RegisterProfilePrefs(registry); chromeos::KeyPermissions::RegisterProfilePrefs(registry);
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index f661e89..c850042c 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc
@@ -36,6 +36,9 @@ // utility methods (IsArcPlayStoreEnabledForProfile() and // SetArcPlayStoreEnabledForProfile()) in chrome/browser/chromeos/arc/arc_util. const char kArcEnabled[] = "arc.enabled"; +// A preference that indicated whether Android reported it's compliance status +// with provided policies. This is used only as a signal to start Android kiosk. +const char kArcPolicyComplianceReported[] = "arc.policy_compliance_reported"; // A preference that indicates that user accepted PlayStore terms. const char kArcTermsAccepted[] = "arc.terms.accepted"; // A preference to keep user's consent to use location service.
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index d26ea9d..8b7f3ed 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -25,6 +25,7 @@ extern const char kArcBackupRestoreEnabled[]; extern const char kArcDataRemoveRequested[]; extern const char kArcEnabled[]; +extern const char kArcPolicyComplianceReported[]; extern const char kArcTermsAccepted[]; extern const char kArcLocationServiceEnabled[]; extern const char kArcPackages[];
diff --git a/components/arc/BUILD.gn b/components/arc/BUILD.gn index 86b774e33..b0ac5a3 100644 --- a/components/arc/BUILD.gn +++ b/components/arc/BUILD.gn
@@ -216,6 +216,7 @@ "intent_helper/link_handler_model_impl_unittest.cc", "intent_helper/local_activity_resolver_unittest.cc", "intent_helper/page_transition_util_unittest.cc", + "kiosk/arc_kiosk_bridge_unittest.cc", ] deps = [ @@ -225,6 +226,7 @@ "//chromeos", "//device/bluetooth", "//mojo/public/cpp/system:system", + "//testing/gmock", "//testing/gtest", "//ui/aura", "//ui/aura:test_support",
diff --git a/components/arc/kiosk/arc_kiosk_bridge_unittest.cc b/components/arc/kiosk/arc_kiosk_bridge_unittest.cc new file mode 100644 index 0000000..b2243f7c --- /dev/null +++ b/components/arc/kiosk/arc_kiosk_bridge_unittest.cc
@@ -0,0 +1,59 @@ +// Copyright 2017 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 <memory> + +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "components/arc/arc_bridge_service.h" +#include "components/arc/kiosk/arc_kiosk_bridge.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +class MockArcKioskBridgeDelegate : public arc::ArcKioskBridge::Delegate { + public: + MockArcKioskBridgeDelegate() = default; + + MOCK_METHOD0(OnMaintenanceSessionCreated, void()); + MOCK_METHOD0(OnMaintenanceSessionFinished, void()); +}; + +} // namespace + +namespace arc { + +class ArcKioskBridgeTest : public testing::Test { + public: + ArcKioskBridgeTest() + : bridge_service_(base::MakeUnique<ArcBridgeService>()), + delegate_(base::MakeUnique<MockArcKioskBridgeDelegate>()), + kiosk_bridge_(base::MakeUnique<ArcKioskBridge>(bridge_service_.get(), + delegate_.get())) {} + + protected: + std::unique_ptr<ArcBridgeService> bridge_service_; + std::unique_ptr<MockArcKioskBridgeDelegate> delegate_; + std::unique_ptr<ArcKioskBridge> kiosk_bridge_; + + private: + DISALLOW_COPY_AND_ASSIGN(ArcKioskBridgeTest); +}; + +TEST_F(ArcKioskBridgeTest, MaintenanceSessionFinished) { + EXPECT_CALL(*delegate_, OnMaintenanceSessionCreated()).Times(1); + kiosk_bridge_->OnMaintenanceSessionCreated(1); + EXPECT_CALL(*delegate_, OnMaintenanceSessionFinished()).Times(1); + kiosk_bridge_->OnMaintenanceSessionFinished(1, true); +} + +TEST_F(ArcKioskBridgeTest, MaintenanceSessionNotFinished) { + EXPECT_CALL(*delegate_, OnMaintenanceSessionCreated()).Times(1); + kiosk_bridge_->OnMaintenanceSessionCreated(1); + EXPECT_CALL(*delegate_, OnMaintenanceSessionFinished()).Times(0); + kiosk_bridge_->OnMaintenanceSessionFinished(2, true); +} + +} // namespace arc
diff --git a/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.cc b/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.cc index 699c3b5a..e83531a6 100644 --- a/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.cc +++ b/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.cc
@@ -174,8 +174,10 @@ // EulaAcceptedNotifier::Observer implementation. void OnEulaAccepted() override { - // Emulate a browser foregrounded event. - scheduler_->OnBrowserForegrounded(); + // Emulate a persistent fetch - we really want to fetch, initially! + // TODO(jkrcal): Find a cleaner solution. This is somewhat hacky and can + // mess up with metrics. + scheduler_->OnPersistentSchedulerWakeUp(); } private:
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 731f573..ef4dfc9 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -1196,14 +1196,10 @@ "renderer_host/media/video_capture_provider.h", "renderer_host/native_web_keyboard_event_aura.cc", "renderer_host/native_web_keyboard_event_mac.mm", - "renderer_host/offscreen_canvas_compositor_frame_sink.cc", - "renderer_host/offscreen_canvas_compositor_frame_sink.h", "renderer_host/offscreen_canvas_compositor_frame_sink_manager.cc", "renderer_host/offscreen_canvas_compositor_frame_sink_manager.h", - "renderer_host/offscreen_canvas_compositor_frame_sink_provider_impl.cc", - "renderer_host/offscreen_canvas_compositor_frame_sink_provider_impl.h", - "renderer_host/offscreen_canvas_surface_factory_impl.cc", - "renderer_host/offscreen_canvas_surface_factory_impl.h", + "renderer_host/offscreen_canvas_provider_impl.cc", + "renderer_host/offscreen_canvas_provider_impl.h", "renderer_host/offscreen_canvas_surface_impl.cc", "renderer_host/offscreen_canvas_surface_impl.h", "renderer_host/overscroll_configuration.cc",
diff --git a/content/browser/renderer_host/media/audio_output_delegate_impl.cc b/content/browser/renderer_host/media/audio_output_delegate_impl.cc index 84aecef..43df0830 100644 --- a/content/browser/renderer_host/media/audio_output_delegate_impl.cc +++ b/content/browser/renderer_host/media/audio_output_delegate_impl.cc
@@ -171,7 +171,7 @@ void AudioOutputDelegateImpl::SendCreatedNotification() { DCHECK_CURRENTLY_ON(BrowserThread::IO); subscriber_->OnStreamCreated(stream_id_, reader_->shared_memory(), - reader_->foreign_socket()); + reader_->TakeForeignSocket()); } void AudioOutputDelegateImpl::UpdatePlayingState(bool playing) {
diff --git a/content/browser/renderer_host/media/audio_output_delegate_impl_unittest.cc b/content/browser/renderer_host/media/audio_output_delegate_impl_unittest.cc index 355cdce4..a3d09fb8 100644 --- a/content/browser/renderer_host/media/audio_output_delegate_impl_unittest.cc +++ b/content/browser/renderer_host/media/audio_output_delegate_impl_unittest.cc
@@ -14,6 +14,7 @@ #include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" +#include "base/sync_socket.h" #include "content/browser/audio_manager_thread.h" #include "content/browser/media/capture/audio_mirroring_manager.h" #include "content/public/browser/browser_thread.h" @@ -71,10 +72,16 @@ class MockEventHandler : public media::AudioOutputDelegate::EventHandler { public: - MOCK_METHOD3(OnStreamCreated, - void(int stream_id, - base::SharedMemory* shared_memory, - base::CancelableSyncSocket* socket)); + void OnStreamCreated(int stream_id, + base::SharedMemory* shared_memory, + std::unique_ptr<base::CancelableSyncSocket> socket) { + EXPECT_EQ(stream_id, kStreamId); + EXPECT_NE(shared_memory, nullptr); + EXPECT_NE(socket.get(), nullptr); + GotOnStreamCreated(); + } + + MOCK_METHOD0(GotOnStreamCreated, void()); MOCK_METHOD1(OnStreamError, void(int stream_id)); }; @@ -114,8 +121,7 @@ void CreateTest(base::Closure done) { EXPECT_CALL(media_observer_, OnCreatingAudioStream(kRenderProcessId, kRenderFrameId)); - EXPECT_CALL(event_handler_, - OnStreamCreated(kStreamId, NotNull(), NotNull())); + EXPECT_CALL(event_handler_, GotOnStreamCreated()); EXPECT_CALL(mirroring_manager_, AddDiverter(kRenderProcessId, kRenderFrameId, NotNull())); @@ -139,8 +145,7 @@ void PlayTest(base::Closure done) { EXPECT_CALL(media_observer_, OnCreatingAudioStream(kRenderProcessId, kRenderFrameId)); - EXPECT_CALL(event_handler_, - OnStreamCreated(kStreamId, NotNull(), NotNull())); + EXPECT_CALL(event_handler_, GotOnStreamCreated()); EXPECT_CALL(mirroring_manager_, AddDiverter(kRenderProcessId, kRenderFrameId, NotNull())); @@ -166,8 +171,7 @@ void PauseTest(base::Closure done) { EXPECT_CALL(media_observer_, OnCreatingAudioStream(kRenderProcessId, kRenderFrameId)); - EXPECT_CALL(event_handler_, - OnStreamCreated(kStreamId, NotNull(), NotNull())); + EXPECT_CALL(event_handler_, GotOnStreamCreated()); EXPECT_CALL(mirroring_manager_, AddDiverter(kRenderProcessId, kRenderFrameId, NotNull())); @@ -193,8 +197,7 @@ void PlayPausePlayTest(base::Closure done) { EXPECT_CALL(media_observer_, OnCreatingAudioStream(kRenderProcessId, kRenderFrameId)); - EXPECT_CALL(event_handler_, - OnStreamCreated(kStreamId, NotNull(), NotNull())); + EXPECT_CALL(event_handler_, GotOnStreamCreated()); EXPECT_CALL(mirroring_manager_, AddDiverter(kRenderProcessId, kRenderFrameId, NotNull())); @@ -222,8 +225,7 @@ void PlayPlayTest(base::Closure done) { EXPECT_CALL(media_observer_, OnCreatingAudioStream(kRenderProcessId, kRenderFrameId)); - EXPECT_CALL(event_handler_, - OnStreamCreated(kStreamId, NotNull(), NotNull())); + EXPECT_CALL(event_handler_, GotOnStreamCreated()); EXPECT_CALL(mirroring_manager_, AddDiverter(kRenderProcessId, kRenderFrameId, NotNull())); @@ -250,8 +252,7 @@ void CreateDivertTest(base::Closure done) { EXPECT_CALL(media_observer_, OnCreatingAudioStream(kRenderProcessId, kRenderFrameId)); - EXPECT_CALL(event_handler_, - OnStreamCreated(kStreamId, NotNull(), NotNull())); + EXPECT_CALL(event_handler_, GotOnStreamCreated()); EXPECT_CALL(mirroring_manager_, AddDiverter(kRenderProcessId, kRenderFrameId, NotNull())); @@ -278,8 +279,7 @@ void CreateDivertPauseTest(base::Closure done) { EXPECT_CALL(media_observer_, OnCreatingAudioStream(kRenderProcessId, kRenderFrameId)); - EXPECT_CALL(event_handler_, - OnStreamCreated(kStreamId, NotNull(), NotNull())); + EXPECT_CALL(event_handler_, GotOnStreamCreated()); EXPECT_CALL(mirroring_manager_, AddDiverter(kRenderProcessId, kRenderFrameId, NotNull())); @@ -309,8 +309,7 @@ void PlayDivertTest(base::Closure done) { EXPECT_CALL(media_observer_, OnCreatingAudioStream(kRenderProcessId, kRenderFrameId)); - EXPECT_CALL(event_handler_, - OnStreamCreated(kStreamId, NotNull(), NotNull())); + EXPECT_CALL(event_handler_, GotOnStreamCreated()); EXPECT_CALL(mirroring_manager_, AddDiverter(kRenderProcessId, kRenderFrameId, NotNull())); @@ -338,8 +337,7 @@ void ErrorTest(base::Closure done) { EXPECT_CALL(media_observer_, OnCreatingAudioStream(kRenderProcessId, kRenderFrameId)); - EXPECT_CALL(event_handler_, - OnStreamCreated(kStreamId, NotNull(), NotNull())); + EXPECT_CALL(event_handler_, GotOnStreamCreated()); EXPECT_CALL(event_handler_, OnStreamError(kStreamId)); EXPECT_CALL(mirroring_manager_, AddDiverter(kRenderProcessId, kRenderFrameId, NotNull())); @@ -386,8 +384,7 @@ void PlayAndDestroyTest(base::Closure done) { EXPECT_CALL(media_observer_, OnCreatingAudioStream(kRenderProcessId, kRenderFrameId)); - EXPECT_CALL(event_handler_, - OnStreamCreated(kStreamId, NotNull(), NotNull())); + EXPECT_CALL(event_handler_, GotOnStreamCreated()); EXPECT_CALL(mirroring_manager_, AddDiverter(kRenderProcessId, kRenderFrameId, NotNull())); EXPECT_CALL(mirroring_manager_, RemoveDiverter(NotNull())); @@ -412,8 +409,7 @@ void ErrorAndDestroyTest(base::Closure done) { EXPECT_CALL(media_observer_, OnCreatingAudioStream(kRenderProcessId, kRenderFrameId)); - EXPECT_CALL(event_handler_, - OnStreamCreated(kStreamId, NotNull(), NotNull())); + EXPECT_CALL(event_handler_, GotOnStreamCreated()); EXPECT_CALL(mirroring_manager_, AddDiverter(kRenderProcessId, kRenderFrameId, NotNull())); EXPECT_CALL(mirroring_manager_, RemoveDiverter(NotNull()));
diff --git a/content/browser/renderer_host/media/audio_renderer_host.cc b/content/browser/renderer_host/media/audio_renderer_host.cc index 2c79886d..5579d05 100644 --- a/content/browser/renderer_host/media/audio_renderer_host.cc +++ b/content/browser/renderer_host/media/audio_renderer_host.cc
@@ -107,7 +107,7 @@ void AudioRendererHost::OnStreamCreated( int stream_id, base::SharedMemory* shared_memory, - base::CancelableSyncSocket* foreign_socket) { + std::unique_ptr<base::CancelableSyncSocket> foreign_socket) { DCHECK_CURRENTLY_ON(BrowserThread::IO); if (!PeerHandle()) {
diff --git a/content/browser/renderer_host/media/audio_renderer_host.h b/content/browser/renderer_host/media/audio_renderer_host.h index 5e4ce65c..eb3c90f 100644 --- a/content/browser/renderer_host/media/audio_renderer_host.h +++ b/content/browser/renderer_host/media/audio_renderer_host.h
@@ -91,9 +91,10 @@ bool OnMessageReceived(const IPC::Message& message) override; // AudioOutputDelegate::EventHandler implementation - void OnStreamCreated(int stream_id, - base::SharedMemory* shared_memory, - base::CancelableSyncSocket* foreign_socket) override; + void OnStreamCreated( + int stream_id, + base::SharedMemory* shared_memory, + std::unique_ptr<base::CancelableSyncSocket> foreign_socket) override; void OnStreamError(int stream_id) override; void OverrideDevicePermissionsForTesting(bool has_access);
diff --git a/content/browser/renderer_host/media/audio_sync_reader.cc b/content/browser/renderer_host/media/audio_sync_reader.cc index bbefb4bf..be6afd9 100644 --- a/content/browser/renderer_host/media/audio_sync_reader.cc +++ b/content/browser/renderer_host/media/audio_sync_reader.cc
@@ -5,6 +5,7 @@ #include "content/browser/renderer_host/media/audio_sync_reader.h" #include <algorithm> +#include <limits> #include <string> #include <utility> @@ -140,6 +141,12 @@ std::move(foreign_socket))); } +std::unique_ptr<base::CancelableSyncSocket> +AudioSyncReader::TakeForeignSocket() { + DCHECK(foreign_socket_); + return std::move(foreign_socket_); +} + // media::AudioOutputController::SyncReader implementations. void AudioSyncReader::RequestMoreData(base::TimeDelta delay, base::TimeTicks delay_timestamp,
diff --git a/content/browser/renderer_host/media/audio_sync_reader.h b/content/browser/renderer_host/media/audio_sync_reader.h index 29d1feb8..9cccff15 100644 --- a/content/browser/renderer_host/media/audio_sync_reader.h +++ b/content/browser/renderer_host/media/audio_sync_reader.h
@@ -41,9 +41,8 @@ const media::AudioParameters& params); base::SharedMemory* shared_memory() const { return shared_memory_.get(); } - base::CancelableSyncSocket* foreign_socket() const { - return foreign_socket_.get(); - } + + std::unique_ptr<base::CancelableSyncSocket> TakeForeignSocket(); // media::AudioOutputController::SyncReader implementations. void RequestMoreData(base::TimeDelta delay,
diff --git a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc index 2e3f8649..23f3e82a 100644 --- a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc +++ b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc
@@ -239,9 +239,11 @@ base::SharedMemory shared_memory; ASSERT_TRUE(shared_memory.CreateAndMapAnonymous(100)); - base::CancelableSyncSocket local, remote; - ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&local, &remote)); - event_handler->OnStreamCreated(kStreamId, &shared_memory, &remote); + auto local = base::MakeUnique<base::CancelableSyncSocket>(); + auto remote = base::MakeUnique<base::CancelableSyncSocket>(); + ASSERT_TRUE( + base::CancelableSyncSocket::CreatePair(local.get(), remote.get())); + event_handler->OnStreamCreated(kStreamId, &shared_memory, std::move(remote)); base::RunLoop().RunUntilIdle(); // Make sure we got the callback from creating stream.
diff --git a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.cc b/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.cc deleted file mode 100644 index 97f1fcf..0000000 --- a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.cc +++ /dev/null
@@ -1,88 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.h" - -#include "base/memory/ptr_util.h" -#include "cc/surfaces/surface.h" -#include "cc/surfaces/surface_manager.h" -#include "content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_provider_impl.h" -#include "mojo/public/cpp/bindings/strong_binding.h" - -namespace content { - -OffscreenCanvasCompositorFrameSink::OffscreenCanvasCompositorFrameSink( - OffscreenCanvasCompositorFrameSinkProviderImpl* provider, - const cc::FrameSinkId& frame_sink_id, - cc::mojom::MojoCompositorFrameSinkRequest request, - cc::mojom::MojoCompositorFrameSinkClientPtr client) - : provider_(provider), - support_(cc::CompositorFrameSinkSupport::Create( - this, - provider->GetSurfaceManager(), - frame_sink_id, - false /* is_root */, - true /* handles_frame_sink_id_invalidation */, - true /* needs_sync_points */)), - client_(std::move(client)), - binding_(this, std::move(request)) { - binding_.set_connection_error_handler( - base::Bind(&OffscreenCanvasCompositorFrameSink::OnClientConnectionLost, - base::Unretained(this))); -} - -OffscreenCanvasCompositorFrameSink::~OffscreenCanvasCompositorFrameSink() { - provider_->OnCompositorFrameSinkClientDestroyed(support_->frame_sink_id()); -} - -void OffscreenCanvasCompositorFrameSink::SetNeedsBeginFrame( - bool needs_begin_frame) { - support_->SetNeedsBeginFrame(needs_begin_frame); -} - -void OffscreenCanvasCompositorFrameSink::SubmitCompositorFrame( - const cc::LocalSurfaceId& local_surface_id, - cc::CompositorFrame frame) { - // TODO(samans): This will need to do something similar to - // GpuCompositorFrameSink. - support_->SubmitCompositorFrame(local_surface_id, std::move(frame)); -} - -void OffscreenCanvasCompositorFrameSink::BeginFrameDidNotSwap( - const cc::BeginFrameAck& begin_frame_ack) { - support_->BeginFrameDidNotSwap(begin_frame_ack); -} - -void OffscreenCanvasCompositorFrameSink::EvictFrame() { - support_->EvictFrame(); -} - -void OffscreenCanvasCompositorFrameSink::DidReceiveCompositorFrameAck( - const cc::ReturnedResourceArray& resources) { - if (client_) - client_->DidReceiveCompositorFrameAck(resources); -} - -void OffscreenCanvasCompositorFrameSink::OnBeginFrame( - const cc::BeginFrameArgs& args) { - if (client_) - client_->OnBeginFrame(args); -} - -void OffscreenCanvasCompositorFrameSink::ReclaimResources( - const cc::ReturnedResourceArray& resources) { - if (client_) - client_->ReclaimResources(resources); -} - -void OffscreenCanvasCompositorFrameSink::WillDrawSurface( - const cc::LocalSurfaceId& local_surface_id, - const gfx::Rect& damage_rect) {} - -void OffscreenCanvasCompositorFrameSink::OnClientConnectionLost() { - provider_->OnCompositorFrameSinkClientConnectionLost( - support_->frame_sink_id()); -} - -} // namespace content
diff --git a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.h b/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.h deleted file mode 100644 index 3110b32b..0000000 --- a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.h +++ /dev/null
@@ -1,61 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_RENDERER_HOST_OFFSCREEN_CANVAS_COMPOSITOR_FRAME_SINK_H_ -#define CONTENT_BROWSER_RENDERER_HOST_OFFSCREEN_CANVAS_COMPOSITOR_FRAME_SINK_H_ - -#include "cc/ipc/compositor_frame.mojom.h" -#include "cc/ipc/mojo_compositor_frame_sink.mojom.h" -#include "cc/resources/transferable_resource.h" -#include "cc/surfaces/compositor_frame_sink_support.h" -#include "cc/surfaces/compositor_frame_sink_support_client.h" -#include "mojo/public/cpp/bindings/strong_binding.h" - -namespace content { - -class OffscreenCanvasCompositorFrameSinkProviderImpl; - -class OffscreenCanvasCompositorFrameSink - : public cc::CompositorFrameSinkSupportClient, - public cc::mojom::MojoCompositorFrameSink { - public: - OffscreenCanvasCompositorFrameSink( - OffscreenCanvasCompositorFrameSinkProviderImpl* provider, - const cc::FrameSinkId& frame_sink_id, - cc::mojom::MojoCompositorFrameSinkRequest request, - cc::mojom::MojoCompositorFrameSinkClientPtr client); - - ~OffscreenCanvasCompositorFrameSink() override; - - // Overridden from cc::mojom::MojoCompositorFrameSink: - void SetNeedsBeginFrame(bool needs_begin_frame) override; - void SubmitCompositorFrame(const cc::LocalSurfaceId& local_surface_id, - cc::CompositorFrame frame) override; - void BeginFrameDidNotSwap(const cc::BeginFrameAck& begin_frame_ack) override; - void EvictFrame() override; - - // Overridden from cc::CompositorFrameSinkSupportClient: - void DidReceiveCompositorFrameAck( - const cc::ReturnedResourceArray& resources) override; - void OnBeginFrame(const cc::BeginFrameArgs& args) override; - void ReclaimResources(const cc::ReturnedResourceArray& resources) override; - void WillDrawSurface(const cc::LocalSurfaceId& local_surface_id, - const gfx::Rect& damage_rect) override; - - private: - void OnClientConnectionLost(); - - OffscreenCanvasCompositorFrameSinkProviderImpl* const provider_; - - std::unique_ptr<cc::CompositorFrameSinkSupport> support_; - cc::mojom::MojoCompositorFrameSinkClientPtr client_; - cc::ReturnedResourceArray surface_returned_resources_; - mojo::Binding<cc::mojom::MojoCompositorFrameSink> binding_; - - DISALLOW_COPY_AND_ASSIGN(OffscreenCanvasCompositorFrameSink); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_RENDERER_HOST_OFFSCREEN_CANVAS_COMPOSITOR_FRAME_SINK_H_
diff --git a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager.cc b/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager.cc index ef4cbcd..4a87ca3 100644 --- a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager.cc +++ b/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager.cc
@@ -31,38 +31,14 @@ return g_manager.Pointer(); } -void OffscreenCanvasCompositorFrameSinkManager::RegisterFrameSinkToParent( - const cc::FrameSinkId& child_frame_sink_id) { - auto surface_iter = registered_surface_instances_.find(child_frame_sink_id); - if (surface_iter == registered_surface_instances_.end()) - return; - OffscreenCanvasSurfaceImpl* surfaceImpl = surface_iter->second; - if (surfaceImpl->parent_frame_sink_id().is_valid()) { - GetSurfaceManager()->RegisterFrameSinkHierarchy( - surfaceImpl->parent_frame_sink_id(), child_frame_sink_id); - } -} - -void OffscreenCanvasCompositorFrameSinkManager::UnregisterFrameSinkFromParent( - const cc::FrameSinkId& child_frame_sink_id) { - auto surface_iter = registered_surface_instances_.find(child_frame_sink_id); - if (surface_iter == registered_surface_instances_.end()) - return; - OffscreenCanvasSurfaceImpl* surfaceImpl = surface_iter->second; - if (surfaceImpl->parent_frame_sink_id().is_valid()) { - GetSurfaceManager()->UnregisterFrameSinkHierarchy( - surfaceImpl->parent_frame_sink_id(), child_frame_sink_id); - } -} - void OffscreenCanvasCompositorFrameSinkManager::OnSurfaceCreated( const cc::SurfaceInfo& surface_info) { auto surface_iter = registered_surface_instances_.find(surface_info.id().frame_sink_id()); if (surface_iter == registered_surface_instances_.end()) return; - OffscreenCanvasSurfaceImpl* surfaceImpl = surface_iter->second; - surfaceImpl->OnSurfaceCreated(surface_info); + OffscreenCanvasSurfaceImpl* surface_impl = surface_iter->second; + surface_impl->OnSurfaceCreated(surface_info); } void OffscreenCanvasCompositorFrameSinkManager::
diff --git a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager.h b/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager.h index 7cd9ea8..2d3a2599 100644 --- a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager.h +++ b/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager.h
@@ -20,12 +20,6 @@ static OffscreenCanvasCompositorFrameSinkManager* GetInstance(); - // Registration of the frame sink with the given frame sink id to its parent - // frame sink (if it has one), so that parent frame is able to send signals - // to it on begin frame. - void RegisterFrameSinkToParent(const cc::FrameSinkId& frame_sink_id); - void UnregisterFrameSinkFromParent(const cc::FrameSinkId& frame_sink_id); - void RegisterOffscreenCanvasSurfaceInstance( const cc::FrameSinkId& frame_sink_id, OffscreenCanvasSurfaceImpl* offscreen_canvas_surface);
diff --git a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_provider_impl.cc b/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_provider_impl.cc deleted file mode 100644 index adef5ba..0000000 --- a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_provider_impl.cc +++ /dev/null
@@ -1,57 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_provider_impl.h" - -#include "base/memory/ptr_util.h" -#include "content/browser/compositor/surface_utils.h" -#include "content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.h" -#include "content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager.h" -#include "mojo/public/cpp/bindings/strong_binding.h" - -namespace content { - -OffscreenCanvasCompositorFrameSinkProviderImpl:: - OffscreenCanvasCompositorFrameSinkProviderImpl() {} - -OffscreenCanvasCompositorFrameSinkProviderImpl:: - ~OffscreenCanvasCompositorFrameSinkProviderImpl() {} - -void OffscreenCanvasCompositorFrameSinkProviderImpl::Add( - blink::mojom::OffscreenCanvasCompositorFrameSinkProviderRequest request) { - bindings_.AddBinding(this, std::move(request)); -} - -void OffscreenCanvasCompositorFrameSinkProviderImpl::CreateCompositorFrameSink( - const cc::FrameSinkId& frame_sink_id, - cc::mojom::MojoCompositorFrameSinkClientPtr client, - cc::mojom::MojoCompositorFrameSinkRequest request) { - compositor_frame_sinks_[frame_sink_id] = - base::MakeUnique<OffscreenCanvasCompositorFrameSink>( - this, frame_sink_id, std::move(request), std::move(client)); - - OffscreenCanvasCompositorFrameSinkManager::GetInstance() - ->RegisterFrameSinkToParent(frame_sink_id); -} - -cc::SurfaceManager* -OffscreenCanvasCompositorFrameSinkProviderImpl::GetSurfaceManager() { - return content::GetSurfaceManager(); -} - -void OffscreenCanvasCompositorFrameSinkProviderImpl:: - OnCompositorFrameSinkClientConnectionLost( - const cc::FrameSinkId& frame_sink_id) { - // TODO(fsamuel, xlai): Investigate why this function is not fired when user - // close down the window that has OffscreenCanvas commit(). - compositor_frame_sinks_.erase(frame_sink_id); -} - -void OffscreenCanvasCompositorFrameSinkProviderImpl:: - OnCompositorFrameSinkClientDestroyed(const cc::FrameSinkId& frame_sink_id) { - OffscreenCanvasCompositorFrameSinkManager::GetInstance() - ->UnregisterFrameSinkFromParent(frame_sink_id); -} - -} // namespace content
diff --git a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_provider_impl.h b/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_provider_impl.h deleted file mode 100644 index 5da4335..0000000 --- a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_provider_impl.h +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_RENDERER_HOST_OFFSCREEN_CANVAS_COMPOSITOR_FRAME_SINK_PROVIDER_IMPL_H_ -#define CONTENT_BROWSER_RENDERER_HOST_OFFSCREEN_CANVAS_COMPOSITOR_FRAME_SINK_PROVIDER_IMPL_H_ - -#include <unordered_map> - -#include "content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.h" -#include "mojo/public/cpp/bindings/binding_set.h" -#include "third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom.h" - -namespace content { - -// TODO(fsamuel): This should be replaced with the FrameSinkManager interface. -class OffscreenCanvasCompositorFrameSinkProviderImpl - : public blink::mojom::OffscreenCanvasCompositorFrameSinkProvider { - public: - OffscreenCanvasCompositorFrameSinkProviderImpl(); - ~OffscreenCanvasCompositorFrameSinkProviderImpl() override; - - void Add( - blink::mojom::OffscreenCanvasCompositorFrameSinkProviderRequest request); - - // blink::mojom::OffscreenCanvasCompositorFrameSinkProvider implementation. - void CreateCompositorFrameSink( - const cc::FrameSinkId& frame_sink_id, - cc::mojom::MojoCompositorFrameSinkClientPtr client, - cc::mojom::MojoCompositorFrameSinkRequest request) override; - - cc::SurfaceManager* GetSurfaceManager(); - - void OnCompositorFrameSinkClientConnectionLost( - const cc::FrameSinkId& frame_sink_id); - void OnCompositorFrameSinkClientDestroyed( - const cc::FrameSinkId& frame_sink_id); - - private: - std::unordered_map<cc::FrameSinkId, - std::unique_ptr<OffscreenCanvasCompositorFrameSink>, - cc::FrameSinkIdHash> - compositor_frame_sinks_; - - mojo::BindingSet<blink::mojom::OffscreenCanvasCompositorFrameSinkProvider> - bindings_; - - DISALLOW_COPY_AND_ASSIGN(OffscreenCanvasCompositorFrameSinkProviderImpl); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_RENDERER_HOST_OFFSCREEN_CANVAS_COMPOSITOR_FRAME_SINK_PROVIDER_IMPL_H_
diff --git a/content/browser/renderer_host/offscreen_canvas_provider_impl.cc b/content/browser/renderer_host/offscreen_canvas_provider_impl.cc new file mode 100644 index 0000000..9d578ad --- /dev/null +++ b/content/browser/renderer_host/offscreen_canvas_provider_impl.cc
@@ -0,0 +1,47 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/renderer_host/offscreen_canvas_provider_impl.h" + +#include "content/browser/compositor/surface_utils.h" +#include "content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager.h" +#include "content/browser/renderer_host/offscreen_canvas_surface_impl.h" + +namespace content { + +OffscreenCanvasProviderImpl::OffscreenCanvasProviderImpl() = default; + +OffscreenCanvasProviderImpl::~OffscreenCanvasProviderImpl() = default; + +void OffscreenCanvasProviderImpl::Add( + blink::mojom::OffscreenCanvasProviderRequest request) { + bindings_.AddBinding(this, std::move(request)); +} + +void OffscreenCanvasProviderImpl::CreateOffscreenCanvasSurface( + const cc::FrameSinkId& parent_frame_sink_id, + const cc::FrameSinkId& frame_sink_id, + cc::mojom::FrameSinkManagerClientPtr client, + blink::mojom::OffscreenCanvasSurfaceRequest request) { + OffscreenCanvasSurfaceImpl::Create(parent_frame_sink_id, frame_sink_id, + std::move(client), std::move(request)); +} + +void OffscreenCanvasProviderImpl::CreateCompositorFrameSink( + const cc::FrameSinkId& frame_sink_id, + cc::mojom::MojoCompositorFrameSinkClientPtr client, + cc::mojom::MojoCompositorFrameSinkRequest request) { + // TODO(kylechar): Add test for bad |frame_sink_id|. + auto* manager = OffscreenCanvasCompositorFrameSinkManager::GetInstance(); + auto* surface_impl = manager->GetSurfaceInstance(frame_sink_id); + if (!surface_impl) { + DLOG(ERROR) << "No OffscreenCanvasSurfaceImpl for " << frame_sink_id; + return; + } + + surface_impl->CreateCompositorFrameSink(std::move(client), + std::move(request)); +} + +} // namespace content
diff --git a/content/browser/renderer_host/offscreen_canvas_provider_impl.h b/content/browser/renderer_host/offscreen_canvas_provider_impl.h new file mode 100644 index 0000000..be2c52c --- /dev/null +++ b/content/browser/renderer_host/offscreen_canvas_provider_impl.h
@@ -0,0 +1,42 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_RENDERER_HOST_OFFSCREEN_CANVAS_PROVIDER_IMPL_H_ +#define CONTENT_BROWSER_RENDERER_HOST_OFFSCREEN_CANVAS_PROVIDER_IMPL_H_ + +#include "cc/surfaces/frame_sink_id.h" +#include "mojo/public/cpp/bindings/binding_set.h" +#include "third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom.h" + +namespace content { + +// Creates OffscreenCanvasSurfaces and MojoCompositorFrameSinks for a renderer. +class OffscreenCanvasProviderImpl + : public blink::mojom::OffscreenCanvasProvider { + public: + OffscreenCanvasProviderImpl(); + ~OffscreenCanvasProviderImpl() override; + + void Add(blink::mojom::OffscreenCanvasProviderRequest request); + + // blink::mojom::OffscreenCanvasProvider implementation. + void CreateOffscreenCanvasSurface( + const cc::FrameSinkId& parent_frame_sink_id, + const cc::FrameSinkId& frame_sink_id, + cc::mojom::FrameSinkManagerClientPtr client, + blink::mojom::OffscreenCanvasSurfaceRequest request) override; + void CreateCompositorFrameSink( + const cc::FrameSinkId& frame_sink_id, + cc::mojom::MojoCompositorFrameSinkClientPtr client, + cc::mojom::MojoCompositorFrameSinkRequest request) override; + + private: + mojo::BindingSet<blink::mojom::OffscreenCanvasProvider> bindings_; + + DISALLOW_COPY_AND_ASSIGN(OffscreenCanvasProviderImpl); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_RENDERER_HOST_OFFSCREEN_CANVAS_PROVIDER_IMPL_H_
diff --git a/content/browser/renderer_host/offscreen_canvas_surface_factory_impl.cc b/content/browser/renderer_host/offscreen_canvas_surface_factory_impl.cc deleted file mode 100644 index 8d101f1..0000000 --- a/content/browser/renderer_host/offscreen_canvas_surface_factory_impl.cc +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/renderer_host/offscreen_canvas_surface_factory_impl.h" - -#include "base/memory/ptr_util.h" -#include "cc/surfaces/frame_sink_id.h" -#include "content/browser/renderer_host/offscreen_canvas_surface_impl.h" -#include "mojo/public/cpp/bindings/strong_binding.h" - -namespace content { - -// static -void OffscreenCanvasSurfaceFactoryImpl::Create( - blink::mojom::OffscreenCanvasSurfaceFactoryRequest request) { - mojo::MakeStrongBinding(base::MakeUnique<OffscreenCanvasSurfaceFactoryImpl>(), - std::move(request)); -} - -void OffscreenCanvasSurfaceFactoryImpl::CreateOffscreenCanvasSurface( - const cc::FrameSinkId& parent_frame_sink_id, - const cc::FrameSinkId& frame_sink_id, - cc::mojom::FrameSinkManagerClientPtr client, - blink::mojom::OffscreenCanvasSurfaceRequest request) { - OffscreenCanvasSurfaceImpl::Create(parent_frame_sink_id, frame_sink_id, - std::move(client), std::move(request)); -} - -} // namespace content
diff --git a/content/browser/renderer_host/offscreen_canvas_surface_factory_impl.h b/content/browser/renderer_host/offscreen_canvas_surface_factory_impl.h deleted file mode 100644 index 879e001..0000000 --- a/content/browser/renderer_host/offscreen_canvas_surface_factory_impl.h +++ /dev/null
@@ -1,35 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_RENDERER_HOST_OFFSCREEN_CANVAS_SURFACE_FACTORY_IMPL_H_ -#define CONTENT_BROWSER_RENDERER_HOST_OFFSCREEN_CANVAS_SURFACE_FACTORY_IMPL_H_ - -#include "cc/ipc/frame_sink_manager.mojom.h" -#include "third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom.h" - -namespace content { - -class OffscreenCanvasSurfaceFactoryImpl - : public blink::mojom::OffscreenCanvasSurfaceFactory { - public: - OffscreenCanvasSurfaceFactoryImpl() {} - ~OffscreenCanvasSurfaceFactoryImpl() override {} - - static void Create( - blink::mojom::OffscreenCanvasSurfaceFactoryRequest request); - - // blink::mojom::OffscreenCanvasSurfaceFactory implementation. - void CreateOffscreenCanvasSurface( - const cc::FrameSinkId& parent_frame_sink_id, - const cc::FrameSinkId& frame_sink_id, - cc::mojom::FrameSinkManagerClientPtr client, - blink::mojom::OffscreenCanvasSurfaceRequest request) override; - - private: - DISALLOW_COPY_AND_ASSIGN(OffscreenCanvasSurfaceFactoryImpl); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_RENDERER_HOST_OFFSCREEN_CANVAS_SURFACE_FACTORY_IMPL_H_
diff --git a/content/browser/renderer_host/offscreen_canvas_surface_impl.cc b/content/browser/renderer_host/offscreen_canvas_surface_impl.cc index dd9218c..48ea6864 100644 --- a/content/browser/renderer_host/offscreen_canvas_surface_impl.cc +++ b/content/browser/renderer_host/offscreen_canvas_surface_impl.cc
@@ -8,11 +8,10 @@ #include "base/bind_helpers.h" #include "base/memory/ptr_util.h" -#include "cc/surfaces/surface.h" #include "cc/surfaces/surface_manager.h" +#include "content/browser/compositor/frame_sink_manager_host.h" #include "content/browser/compositor/surface_utils.h" #include "content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager.h" -#include "content/public/browser/browser_thread.h" namespace content { @@ -28,10 +27,12 @@ } OffscreenCanvasSurfaceImpl::~OffscreenCanvasSurfaceImpl() { - if (frame_sink_id_.is_valid()) { - OffscreenCanvasCompositorFrameSinkManager::GetInstance() - ->UnregisterOffscreenCanvasSurfaceInstance(frame_sink_id_); + if (has_created_compositor_frame_sink_) { + GetFrameSinkManagerHost()->UnregisterFrameSinkHierarchy( + parent_frame_sink_id_, frame_sink_id_); } + OffscreenCanvasCompositorFrameSinkManager::GetInstance() + ->UnregisterOffscreenCanvasSurfaceInstance(frame_sink_id_); } // static @@ -48,6 +49,23 @@ mojo::MakeStrongBinding(std::move(impl), std::move(request)); } +void OffscreenCanvasSurfaceImpl::CreateCompositorFrameSink( + cc::mojom::MojoCompositorFrameSinkClientPtr client, + cc::mojom::MojoCompositorFrameSinkRequest request) { + if (has_created_compositor_frame_sink_) { + DLOG(ERROR) << "CreateCompositorFrameSink() called more than once."; + return; + } + + GetFrameSinkManagerHost()->CreateCompositorFrameSink( + frame_sink_id_, std::move(request), + mojo::MakeRequest(&compositor_frame_sink_private_), std::move(client)); + + GetFrameSinkManagerHost()->RegisterFrameSinkHierarchy(parent_frame_sink_id_, + frame_sink_id_); + has_created_compositor_frame_sink_ = true; +} + void OffscreenCanvasSurfaceImpl::OnSurfaceCreated( const cc::SurfaceInfo& surface_info) { DCHECK_EQ(surface_info.id().frame_sink_id(), frame_sink_id_);
diff --git a/content/browser/renderer_host/offscreen_canvas_surface_impl.h b/content/browser/renderer_host/offscreen_canvas_surface_impl.h index ab3bcb2..3f76a2b 100644 --- a/content/browser/renderer_host/offscreen_canvas_surface_impl.h +++ b/content/browser/renderer_host/offscreen_canvas_surface_impl.h
@@ -7,12 +7,13 @@ #include "cc/ipc/frame_sink_manager.mojom.h" #include "cc/surfaces/surface_id.h" -#include "mojo/public/cpp/bindings/interface_request.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom.h" namespace content { +// The browser owned object for an offscreen canvas connection. Holds +// connections to both the renderer and frame sink manager. class CONTENT_EXPORT OffscreenCanvasSurfaceImpl : public blink::mojom::OffscreenCanvasSurface { public: @@ -26,6 +27,14 @@ cc::mojom::FrameSinkManagerClientPtr client, blink::mojom::OffscreenCanvasSurfaceRequest request); + // Creates a MojoCompositorFrameSink connection to FrameSinkManager for an + // offscreen canvas client. The corresponding private interface will be owned + // here to control CompositorFrameSink lifetime. This should only ever be + // called once. + void CreateCompositorFrameSink( + cc::mojom::MojoCompositorFrameSinkClientPtr client, + cc::mojom::MojoCompositorFrameSinkRequest request); + void OnSurfaceCreated(const cc::SurfaceInfo& surface_info); // blink::mojom::OffscreenCanvasSurface implementation. @@ -47,11 +56,18 @@ cc::mojom::FrameSinkManagerClientPtr client_; mojo::StrongBindingPtr<blink::mojom::OffscreenCanvasSurface> binding_; + // Private connection for the CompositorFrameSink. The CompositorFrameSink + // will not be destroyed until both private and offscreen canvas client + // connections are closed. + cc::mojom::MojoCompositorFrameSinkPrivatePtr compositor_frame_sink_private_; + // Surface-related state const cc::FrameSinkId frame_sink_id_; cc::LocalSurfaceId current_local_surface_id_; const cc::FrameSinkId parent_frame_sink_id_; + bool has_created_compositor_frame_sink_ = false; + DISALLOW_COPY_AND_ASSIGN(OffscreenCanvasSurfaceImpl); };
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index 05f7cfe..9986ff6 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -109,8 +109,7 @@ #include "content/browser/renderer_host/media/media_stream_dispatcher_host.h" #include "content/browser/renderer_host/media/peer_connection_tracker_host.h" #include "content/browser/renderer_host/media/video_capture_host.h" -#include "content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_provider_impl.h" -#include "content/browser/renderer_host/offscreen_canvas_surface_factory_impl.h" +#include "content/browser/renderer_host/offscreen_canvas_provider_impl.h" #include "content/browser/renderer_host/pepper/pepper_message_filter.h" #include "content/browser/renderer_host/pepper/pepper_renderer_connection.h" #include "content/browser/renderer_host/render_message_filter.h" @@ -1238,16 +1237,13 @@ AddUIThreadInterface( registry.get(), - base::Bind(&RenderProcessHostImpl:: - CreateOffscreenCanvasCompositorFrameSinkProvider, + base::Bind(&RenderProcessHostImpl::CreateOffscreenCanvasProvider, base::Unretained(this))); AddUIThreadInterface(registry.get(), base::Bind(&RenderProcessHostImpl::BindFrameSinkProvider, base::Unretained(this))); - AddUIThreadInterface(registry.get(), - base::Bind(&OffscreenCanvasSurfaceFactoryImpl::Create)); AddUIThreadInterface( registry.get(), base::Bind(&BackgroundSyncContext::CreateService, @@ -1363,12 +1359,12 @@ gpu_client_->Add(std::move(request)); } -void RenderProcessHostImpl::CreateOffscreenCanvasCompositorFrameSinkProvider( - blink::mojom::OffscreenCanvasCompositorFrameSinkProviderRequest request) { +void RenderProcessHostImpl::CreateOffscreenCanvasProvider( + blink::mojom::OffscreenCanvasProviderRequest request) { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (!offscreen_canvas_provider_) { - offscreen_canvas_provider_.reset( - new OffscreenCanvasCompositorFrameSinkProviderImpl()); + offscreen_canvas_provider_ = + base::MakeUnique<OffscreenCanvasProviderImpl>(); } offscreen_canvas_provider_->Add(std::move(request)); }
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h index 7ef0f6a..aa6898d 100644 --- a/content/browser/renderer_host/render_process_host_impl.h +++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -24,7 +24,7 @@ #include "content/browser/child_process_launcher.h" #include "content/browser/dom_storage/session_storage_namespace_impl.h" #include "content/browser/renderer_host/frame_sink_provider_impl.h" -#include "content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_provider_impl.h" +#include "content/browser/renderer_host/offscreen_canvas_provider_impl.h" #include "content/browser/webrtc/webrtc_eventlog_host.h" #include "content/common/associated_interfaces.mojom.h" #include "content/common/content_export.h" @@ -347,8 +347,8 @@ mojom::AssociatedInterfaceAssociatedRequest request) override; void CreateMusGpuRequest(ui::mojom::GpuRequest request); - void CreateOffscreenCanvasCompositorFrameSinkProvider( - blink::mojom::OffscreenCanvasCompositorFrameSinkProviderRequest request); + void CreateOffscreenCanvasProvider( + blink::mojom::OffscreenCanvasProviderRequest request); void BindFrameSinkProvider(mojom::FrameSinkProviderRequest request); void CreateStoragePartitionService( mojo::InterfaceRequest<mojom::StoragePartitionService> request); @@ -606,8 +606,7 @@ std::unique_ptr<PushMessagingManager, BrowserThread::DeleteOnIOThread> push_messaging_manager_; - std::unique_ptr<OffscreenCanvasCompositorFrameSinkProviderImpl> - offscreen_canvas_provider_; + std::unique_ptr<OffscreenCanvasProviderImpl> offscreen_canvas_provider_; mojom::RouteProviderAssociatedPtr remote_route_provider_; mojom::RendererAssociatedPtr renderer_interface_;
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json index 0fedcfd..8100d6d 100644 --- a/content/public/app/mojo/content_browser_manifest.json +++ b/content/public/app/mojo/content_browser_manifest.json
@@ -21,8 +21,7 @@ "blink::mojom::Hyphenation", "blink::mojom::MimeRegistry", "blink::mojom::NotificationService", - "blink::mojom::OffscreenCanvasCompositorFrameSinkProvider", - "blink::mojom::OffscreenCanvasSurfaceFactory", + "blink::mojom::OffscreenCanvasProvider", "blink::mojom::PermissionService", "blink::mojom::WebSocket", "content::mojom::FieldTrialRecorder",
diff --git a/gpu/ipc/client/gpu_memory_buffer_impl_native_pixmap.cc b/gpu/ipc/client/gpu_memory_buffer_impl_native_pixmap.cc index c4d900f4..12b1da6 100644 --- a/gpu/ipc/client/gpu_memory_buffer_impl_native_pixmap.cc +++ b/gpu/ipc/client/gpu_memory_buffer_impl_native_pixmap.cc
@@ -84,9 +84,6 @@ bool GpuMemoryBufferImplNativePixmap::IsConfigurationSupported( gfx::BufferFormat format, gfx::BufferUsage usage) { -#if defined(OS_LINUX) - return false; -#endif return gpu::IsNativeGpuMemoryBufferConfigurationSupported(format, usage); }
diff --git a/gpu/ipc/common/gpu_memory_buffer_support.cc b/gpu/ipc/common/gpu_memory_buffer_support.cc index 73ac6b6..77f98359 100644 --- a/gpu/ipc/common/gpu_memory_buffer_support.cc +++ b/gpu/ipc/common/gpu_memory_buffer_support.cc
@@ -7,8 +7,8 @@ #include "base/logging.h" #include "build/build_config.h" -#if defined(USE_OZONE) -#include "ui/ozone/public/client_native_pixmap_factory_ozone.h" +#if defined(OS_LINUX) +#include "ui/gfx/client_native_pixmap_factory.h" #endif namespace gpu { @@ -17,7 +17,7 @@ #if defined(OS_MACOSX) return gfx::IO_SURFACE_BUFFER; #endif -#if defined(USE_OZONE) +#if defined(OS_LINUX) return gfx::NATIVE_PIXMAP; #endif return gfx::EMPTY_BUFFER; @@ -47,7 +47,7 @@ return false; #endif -#if defined(USE_OZONE) +#if defined(OS_LINUX) if (!gfx::ClientNativePixmapFactory::GetInstance()) { // unittests don't have to set ClientNativePixmapFactory. return false;
diff --git a/gpu/ipc/service/BUILD.gn b/gpu/ipc/service/BUILD.gn index b0e1540..abec3f8b 100644 --- a/gpu/ipc/service/BUILD.gn +++ b/gpu/ipc/service/BUILD.gn
@@ -112,16 +112,16 @@ libs += [ "android" ] } if (is_linux) { - sources += [ "image_transport_surface_linux.cc" ] + sources += [ + "gpu_memory_buffer_factory_native_pixmap.cc", + "gpu_memory_buffer_factory_native_pixmap.h", + "image_transport_surface_linux.cc", + ] } if (use_x11) { sources += [ "x_util.h" ] } if (use_ozone) { - sources += [ - "gpu_memory_buffer_factory_ozone_native_pixmap.cc", - "gpu_memory_buffer_factory_ozone_native_pixmap.h", - ] deps += [ "//ui/ozone" ] } } @@ -177,8 +177,10 @@ if (is_mac) { sources += [ "gpu_memory_buffer_factory_io_surface_unittest.cc" ] } + if (is_linux) { + sources += [ "gpu_memory_buffer_factory_native_pixmap_unittest.cc" ] + } if (use_ozone) { - sources += [ "gpu_memory_buffer_factory_ozone_native_pixmap_unittest.cc" ] deps += [ "//ui/ozone" ] } }
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory.cc b/gpu/ipc/service/gpu_memory_buffer_factory.cc index 3204827..8e179a4 100644 --- a/gpu/ipc/service/gpu_memory_buffer_factory.cc +++ b/gpu/ipc/service/gpu_memory_buffer_factory.cc
@@ -12,8 +12,8 @@ #include "gpu/ipc/service/gpu_memory_buffer_factory_io_surface.h" #endif -#if defined(USE_OZONE) -#include "gpu/ipc/service/gpu_memory_buffer_factory_ozone_native_pixmap.h" +#if defined(OS_LINUX) +#include "gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h" #endif namespace gpu { @@ -24,8 +24,8 @@ #if defined(OS_MACOSX) return base::WrapUnique(new GpuMemoryBufferFactoryIOSurface); #endif -#if defined(USE_OZONE) - return base::WrapUnique(new GpuMemoryBufferFactoryOzoneNativePixmap); +#if defined(OS_LINUX) + return base::WrapUnique(new GpuMemoryBufferFactoryNativePixmap); #endif return nullptr; }
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_ozone_native_pixmap.cc b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc similarity index 75% rename from gpu/ipc/service/gpu_memory_buffer_factory_ozone_native_pixmap.cc rename to gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc index 955f0abb..cc08eb86 100644 --- a/gpu/ipc/service/gpu_memory_buffer_factory_ozone_native_pixmap.cc +++ b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc
@@ -2,31 +2,32 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "gpu/ipc/service/gpu_memory_buffer_factory_ozone_native_pixmap.h" +#include "gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h" #include "ui/gfx/client_native_pixmap.h" #include "ui/gfx/native_pixmap.h" #include "ui/gl/gl_image_native_pixmap.h" -#include "ui/ozone/public/client_native_pixmap_factory_ozone.h" + +#if defined(USE_OZONE) #include "ui/ozone/public/ozone_platform.h" #include "ui/ozone/public/surface_factory_ozone.h" +#endif namespace gpu { -GpuMemoryBufferFactoryOzoneNativePixmap:: - GpuMemoryBufferFactoryOzoneNativePixmap() {} +GpuMemoryBufferFactoryNativePixmap::GpuMemoryBufferFactoryNativePixmap() {} -GpuMemoryBufferFactoryOzoneNativePixmap:: - ~GpuMemoryBufferFactoryOzoneNativePixmap() {} +GpuMemoryBufferFactoryNativePixmap::~GpuMemoryBufferFactoryNativePixmap() {} gfx::GpuMemoryBufferHandle -GpuMemoryBufferFactoryOzoneNativePixmap::CreateGpuMemoryBuffer( +GpuMemoryBufferFactoryNativePixmap::CreateGpuMemoryBuffer( gfx::GpuMemoryBufferId id, const gfx::Size& size, gfx::BufferFormat format, gfx::BufferUsage usage, int client_id, SurfaceHandle surface_handle) { +#if defined(USE_OZONE) scoped_refptr<gfx::NativePixmap> pixmap = ui::OzonePlatform::GetInstance() ->GetSurfaceFactoryOzone() @@ -52,9 +53,13 @@ } return new_handle; +#else + NOTIMPLEMENTED(); + return gfx::GpuMemoryBufferHandle(); +#endif } -void GpuMemoryBufferFactoryOzoneNativePixmap::DestroyGpuMemoryBuffer( +void GpuMemoryBufferFactoryNativePixmap::DestroyGpuMemoryBuffer( gfx::GpuMemoryBufferId id, int client_id) { base::AutoLock lock(native_pixmaps_lock_); @@ -62,12 +67,12 @@ native_pixmaps_.erase(key); } -ImageFactory* GpuMemoryBufferFactoryOzoneNativePixmap::AsImageFactory() { +ImageFactory* GpuMemoryBufferFactoryNativePixmap::AsImageFactory() { return this; } scoped_refptr<gl::GLImage> -GpuMemoryBufferFactoryOzoneNativePixmap::CreateImageForGpuMemoryBuffer( +GpuMemoryBufferFactoryNativePixmap::CreateImageForGpuMemoryBuffer( const gfx::GpuMemoryBufferHandle& handle, const gfx::Size& size, gfx::BufferFormat format, @@ -90,10 +95,16 @@ // Create new pixmap from handle if one doesn't already exist. if (!pixmap) { +#if defined(USE_OZONE) pixmap = ui::OzonePlatform::GetInstance() ->GetSurfaceFactoryOzone() ->CreateNativePixmapFromHandle(surface_handle, size, format, handle.native_pixmap_handle); +#else + // TODO(j.isorce): implement this to enable glCreateImageCHROMIUM on Linux. + // On going in http://codereview.chromium.org/2705213005, crbug.com/584248. + NOTIMPLEMENTED(); +#endif if (!pixmap.get()) { DLOG(ERROR) << "Failed to create pixmap from handle"; return nullptr; @@ -117,15 +128,19 @@ } scoped_refptr<gl::GLImage> -GpuMemoryBufferFactoryOzoneNativePixmap::CreateAnonymousImage( +GpuMemoryBufferFactoryNativePixmap::CreateAnonymousImage( const gfx::Size& size, gfx::BufferFormat format, unsigned internalformat) { - scoped_refptr<gfx::NativePixmap> pixmap = - ui::OzonePlatform::GetInstance() - ->GetSurfaceFactoryOzone() - ->CreateNativePixmap(gpu::kNullSurfaceHandle, size, format, - gfx::BufferUsage::SCANOUT); + scoped_refptr<gfx::NativePixmap> pixmap; +#if defined(USE_OZONE) + pixmap = ui::OzonePlatform::GetInstance() + ->GetSurfaceFactoryOzone() + ->CreateNativePixmap(gpu::kNullSurfaceHandle, size, format, + gfx::BufferUsage::SCANOUT); +#else + NOTIMPLEMENTED(); +#endif if (!pixmap.get()) { LOG(ERROR) << "Failed to create pixmap " << size.ToString() << " format " << static_cast<int>(format); @@ -141,7 +156,7 @@ return image; } -unsigned GpuMemoryBufferFactoryOzoneNativePixmap::RequiredTextureType() { +unsigned GpuMemoryBufferFactoryNativePixmap::RequiredTextureType() { return GL_TEXTURE_EXTERNAL_OES; }
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_ozone_native_pixmap.h b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h similarity index 81% rename from gpu/ipc/service/gpu_memory_buffer_factory_ozone_native_pixmap.h rename to gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h index 9bb4db7..463d0682 100644 --- a/gpu/ipc/service/gpu_memory_buffer_factory_ozone_native_pixmap.h +++ b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef GPU_IPC_SERVICE_GPU_MEMORY_BUFFER_FACTORY_OZONE_NATIVE_PIXMAP_H_ -#define GPU_IPC_SERVICE_GPU_MEMORY_BUFFER_FACTORY_OZONE_NATIVE_PIXMAP_H_ +#ifndef GPU_IPC_SERVICE_GPU_MEMORY_BUFFER_FACTORY_NATIVE_PIXMAP_H_ +#define GPU_IPC_SERVICE_GPU_MEMORY_BUFFER_FACTORY_NATIVE_PIXMAP_H_ #include <unordered_map> #include <utility> @@ -22,12 +22,12 @@ namespace gpu { -class GPU_EXPORT GpuMemoryBufferFactoryOzoneNativePixmap +class GPU_EXPORT GpuMemoryBufferFactoryNativePixmap : public GpuMemoryBufferFactory, public ImageFactory { public: - GpuMemoryBufferFactoryOzoneNativePixmap(); - ~GpuMemoryBufferFactoryOzoneNativePixmap() override; + GpuMemoryBufferFactoryNativePixmap(); + ~GpuMemoryBufferFactoryNativePixmap() override; // Overridden from GpuMemoryBufferFactory: gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer( @@ -64,9 +64,9 @@ NativePixmapMap native_pixmaps_; base::Lock native_pixmaps_lock_; - DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferFactoryOzoneNativePixmap); + DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferFactoryNativePixmap); }; } // namespace gpu -#endif // GPU_IPC_SERVICE_GPU_MEMORY_BUFFER_FACTORY_OZONE_NATIVE_PIXMAP_H_ +#endif // GPU_IPC_SERVICE_GPU_MEMORY_BUFFER_FACTORY_NATIVE_PIXMAP_H_
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_ozone_native_pixmap_unittest.cc b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap_unittest.cc similarity index 62% rename from gpu/ipc/service/gpu_memory_buffer_factory_ozone_native_pixmap_unittest.cc rename to gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap_unittest.cc index 7fcf626..2c381184 100644 --- a/gpu/ipc/service/gpu_memory_buffer_factory_ozone_native_pixmap_unittest.cc +++ b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap_unittest.cc
@@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "gpu/ipc/service/gpu_memory_buffer_factory_ozone_native_pixmap.h" +#include "gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h" #include "gpu/ipc/service/gpu_memory_buffer_factory_test_template.h" namespace gpu { namespace { -INSTANTIATE_TYPED_TEST_CASE_P(GpuMemoryBufferFactoryOzoneNativePixmap, +INSTANTIATE_TYPED_TEST_CASE_P(GpuMemoryBufferFactoryNativePixmap, GpuMemoryBufferFactoryTest, - GpuMemoryBufferFactoryOzoneNativePixmap); + GpuMemoryBufferFactoryNativePixmap); } // namespace } // namespace gpu
diff --git a/headless/BUILD.gn b/headless/BUILD.gn index ea8089c..67dcbb4 100644 --- a/headless/BUILD.gn +++ b/headless/BUILD.gn
@@ -438,7 +438,6 @@ "lib/headless_web_contents_browsertest.cc", "public/util/dom_tree_extractor_browsertest.cc", "public/util/flat_dom_tree_extractor_browsertest.cc", - "public/util/protocol_handler_request_id_browsertest.cc", "test/headless_browser_test.cc", "test/headless_browser_test.h", "test/headless_test_launcher.cc",
diff --git a/headless/public/util/deterministic_http_protocol_handler.cc b/headless/public/util/deterministic_http_protocol_handler.cc index 6a186b99..dd905b64 100644 --- a/headless/public/util/deterministic_http_protocol_handler.cc +++ b/headless/public/util/deterministic_http_protocol_handler.cc
@@ -22,27 +22,20 @@ ~NopGenericURLRequestJobDelegate() override {} // GenericURLRequestJob::Delegate methods: - bool BlockOrRewriteRequest( - const GURL& url, - const std::string& devtools_id, - const std::string& method, - const std::string& referrer, - GenericURLRequestJob::RewriteCallback callback) override { - return false; + void OnPendingRequest(PendingRequest* pending_request) override { + pending_request->AllowRequest(); } - const GenericURLRequestJob::HttpResponse* MaybeMatchResource( - const GURL& url, - const std::string& devtools_id, - const std::string& method, - const net::HttpRequestHeaders& request_headers) override { - return nullptr; + void OnResourceLoadFailed(const Request* request, net::Error error) override { } - void OnResourceLoadComplete(const GURL& final_url, - const std::string& devtools_id, - const std::string& mime_type, - int http_response_code) override {} + void OnResourceLoadComplete( + const Request* request, + const GURL& final_url, + int http_response_code, + scoped_refptr<net::HttpResponseHeaders> response_headers, + const char* body, + size_t body_size) override {} private: DISALLOW_COPY_AND_ASSIGN(NopGenericURLRequestJobDelegate);
diff --git a/headless/public/util/generic_url_request_job.cc b/headless/public/util/generic_url_request_job.cc index 83d9f8f86..b618913e 100644 --- a/headless/public/util/generic_url_request_job.cc +++ b/headless/public/util/generic_url_request_job.cc
@@ -8,10 +8,14 @@ #include <algorithm> #include "base/logging.h" +#include "content/public/browser/devtools_agent_host.h" +#include "content/public/browser/resource_request_info.h" +#include "content/public/browser/web_contents.h" #include "headless/public/util/url_request_dispatcher.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" +#include "net/base/upload_bytes_element_reader.h" #include "net/cookies/cookie_store.h" #include "net/http/http_response_headers.h" #include "net/url_request/url_request_context.h" @@ -42,6 +46,8 @@ url_fetcher_(std::move(url_fetcher)), origin_task_runner_(base::ThreadTaskRunnerHandle::Get()), delegate_(delegate), + request_resource_info_( + content::ResourceRequestInfo::ForRequest(request_)), weak_factory_(this) {} GenericURLRequestJob::~GenericURLRequestJob() { @@ -53,67 +59,21 @@ DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); extra_request_headers_ = headers; - if (extra_request_headers_.GetHeader(kDevtoolsRequestId, - &devtools_request_id_)) { - extra_request_headers_.RemoveHeader(kDevtoolsRequestId); - } + // TODO(alexclarke): Remove kDevtoolsRequestId + extra_request_headers_.RemoveHeader(kDevtoolsRequestId); } void GenericURLRequestJob::Start() { - DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); - if (!delegate_->BlockOrRewriteRequest( - request_->url(), devtools_request_id_, request_->method(), - request_->referrer(), - base::Bind(&GenericURLRequestJob::OnRewriteResult, - weak_factory_.GetWeakPtr(), origin_task_runner_))) { - PrepareCookies(request_->url(), request_->method(), - url::Origin(request_->first_party_for_cookies())); - } + PrepareCookies(request_->url(), request_->method(), + url::Origin(request_->first_party_for_cookies()), + base::Bind(&Delegate::OnPendingRequest, + base::Unretained(delegate_), this)); } -// static -void GenericURLRequestJob::OnRewriteResult( - base::WeakPtr<GenericURLRequestJob> weak_this, - const scoped_refptr<base::SingleThreadTaskRunner>& origin_task_runner, - RewriteResult result, - const GURL& url, - const std::string& method) { - if (!origin_task_runner->RunsTasksOnCurrentThread()) { - origin_task_runner->PostTask( - FROM_HERE, - base::Bind(&GenericURLRequestJob::OnRewriteResultOnOriginThread, - weak_this, result, url, method)); - return; - } - if (weak_this) - weak_this->OnRewriteResultOnOriginThread(result, url, method); -} - -void GenericURLRequestJob::OnRewriteResultOnOriginThread( - RewriteResult result, - const GURL& url, - const std::string& method) { - DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); - switch (result) { - case RewriteResult::kAllow: - // Note that we use the rewritten url for selecting cookies. - // Also, rewriting does not affect the request initiator. - PrepareCookies(url, method, url::Origin(url)); - break; - case RewriteResult::kDeny: - DispatchStartError(net::ERR_FILE_NOT_FOUND); - break; - case RewriteResult::kFailure: - DispatchStartError(net::ERR_UNEXPECTED); - break; - default: - DCHECK(false); - } -}; - void GenericURLRequestJob::PrepareCookies(const GURL& rewritten_url, const std::string& method, - const url::Origin& site_for_cookies) { + const url::Origin& site_for_cookies, + const base::Closure& done_callback) { DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); net::CookieStore* cookie_store = request_->context()->cookie_store(); net::CookieOptions options; @@ -138,12 +98,14 @@ cookie_store->GetCookieListWithOptionsAsync( rewritten_url, options, base::Bind(&GenericURLRequestJob::OnCookiesAvailable, - weak_factory_.GetWeakPtr(), rewritten_url, method)); + weak_factory_.GetWeakPtr(), rewritten_url, method, + done_callback)); } void GenericURLRequestJob::OnCookiesAvailable( const GURL& rewritten_url, const std::string& method, + const base::Closure& done_callback, const net::CookieList& cookie_list) { DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); // TODO(alexclarke): Set user agent. @@ -155,23 +117,13 @@ extra_request_headers_.SetHeader(net::HttpRequestHeaders::kReferer, request_->referrer()); - // The resource may have been supplied in the request. - const HttpResponse* matched_resource = delegate_->MaybeMatchResource( - rewritten_url, devtools_request_id_, method, extra_request_headers_); - - if (matched_resource) { - OnFetchCompleteExtractHeaders( - matched_resource->final_url, matched_resource->http_response_code, - matched_resource->response_data, matched_resource->response_data_size); - } else { - url_fetcher_->StartFetch(rewritten_url, method, extra_request_headers_, - devtools_request_id_, this); - } + done_callback.Run(); } void GenericURLRequestJob::OnFetchStartError(net::Error error) { DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); DispatchStartError(error); + delegate_->OnResourceLoadFailed(this, error); } void GenericURLRequestJob::OnFetchComplete( @@ -189,11 +141,8 @@ DispatchHeadersComplete(); - std::string mime_type; - GetMimeType(&mime_type); - - delegate_->OnResourceLoadComplete(final_url, devtools_request_id_, mime_type, - http_response_code); + delegate_->OnResourceLoadComplete(this, final_url, http_response_code, + response_headers_, body_, body_size_); } int GenericURLRequestJob::ReadRawData(net::IOBuffer* buf, int buf_size) { @@ -236,4 +185,145 @@ load_timing_info->receive_headers_end = response_time_; } +const net::URLRequest* GenericURLRequestJob::GetURLRequest() const { + return request_; +} + +int GenericURLRequestJob::GetFrameTreeNodeId() const { + return request_resource_info_->GetFrameTreeNodeId(); +} + +std::string GenericURLRequestJob::GetDevToolsAgentHostId() const { + return content::DevToolsAgentHost::GetOrCreateFor( + request_resource_info_->GetWebContentsGetterForRequest().Run()) + ->GetId(); +} + +Request::ResourceType GenericURLRequestJob::GetResourceType() const { + switch (request_resource_info_->GetResourceType()) { + case content::RESOURCE_TYPE_MAIN_FRAME: + return Request::ResourceType::MAIN_FRAME; + case content::RESOURCE_TYPE_SUB_FRAME: + return Request::ResourceType::SUB_FRAME; + case content::RESOURCE_TYPE_STYLESHEET: + return Request::ResourceType::STYLESHEET; + case content::RESOURCE_TYPE_SCRIPT: + return Request::ResourceType::SCRIPT; + case content::RESOURCE_TYPE_IMAGE: + return Request::ResourceType::IMAGE; + case content::RESOURCE_TYPE_FONT_RESOURCE: + return Request::ResourceType::FONT_RESOURCE; + case content::RESOURCE_TYPE_SUB_RESOURCE: + return Request::ResourceType::SUB_RESOURCE; + case content::RESOURCE_TYPE_OBJECT: + return Request::ResourceType::OBJECT; + case content::RESOURCE_TYPE_MEDIA: + return Request::ResourceType::MEDIA; + case content::RESOURCE_TYPE_WORKER: + return Request::ResourceType::WORKER; + case content::RESOURCE_TYPE_SHARED_WORKER: + return Request::ResourceType::SHARED_WORKER; + case content::RESOURCE_TYPE_PREFETCH: + return Request::ResourceType::PREFETCH; + case content::RESOURCE_TYPE_FAVICON: + return Request::ResourceType::FAVICON; + case content::RESOURCE_TYPE_XHR: + return Request::ResourceType::XHR; + case content::RESOURCE_TYPE_PING: + return Request::ResourceType::PING; + case content::RESOURCE_TYPE_SERVICE_WORKER: + return Request::ResourceType::SERVICE_WORKER; + case content::RESOURCE_TYPE_CSP_REPORT: + return Request::ResourceType::CSP_REPORT; + case content::RESOURCE_TYPE_PLUGIN_RESOURCE: + return Request::ResourceType::PLUGIN_RESOURCE; + default: + NOTREACHED() << "Unrecognized resource type"; + return Request::ResourceType::MAIN_FRAME; + } +} + +namespace { +std::string GetUploadData(net::URLRequest* request) { + if (!request->has_upload()) + return ""; + + const net::UploadDataStream* stream = request->get_upload(); + if (!stream->GetElementReaders()) + return ""; + + DCHECK_EQ(1u, stream->GetElementReaders()->size()); + const net::UploadBytesElementReader* reader = + (*stream->GetElementReaders())[0]->AsBytesReader(); + return std::string(reader->bytes(), reader->length()); +} +} // namespace + +const Request* GenericURLRequestJob::GetRequest() const { + return this; +} + +void GenericURLRequestJob::AllowRequest() { + if (!origin_task_runner_->RunsTasksOnCurrentThread()) { + origin_task_runner_->PostTask( + FROM_HERE, base::Bind(&GenericURLRequestJob::AllowRequest, + weak_factory_.GetWeakPtr())); + return; + } + + url_fetcher_->StartFetch(request_->url(), request_->method(), + GetUploadData(request_), extra_request_headers_, + this); +} + +void GenericURLRequestJob::BlockRequest(net::Error error) { + if (!origin_task_runner_->RunsTasksOnCurrentThread()) { + origin_task_runner_->PostTask( + FROM_HERE, base::Bind(&GenericURLRequestJob::BlockRequest, + weak_factory_.GetWeakPtr(), error)); + return; + } + + DispatchStartError(error); +} + +void GenericURLRequestJob::ModifyRequest( + const GURL& url, + const std::string& method, + const std::string& post_data, + const net::HttpRequestHeaders& request_headers) { + if (!origin_task_runner_->RunsTasksOnCurrentThread()) { + origin_task_runner_->PostTask( + FROM_HERE, base::Bind(&GenericURLRequestJob::ModifyRequest, + weak_factory_.GetWeakPtr(), url, method, + post_data, request_headers)); + return; + } + + extra_request_headers_ = request_headers; + PrepareCookies( + request_->url(), request_->method(), + url::Origin(request_->first_party_for_cookies()), + base::Bind(&URLFetcher::StartFetch, base::Unretained(url_fetcher_.get()), + url, method, post_data, request_headers, this)); +} + +void GenericURLRequestJob::MockResponse( + std::unique_ptr<MockResponseData> mock_response) { + if (!origin_task_runner_->RunsTasksOnCurrentThread()) { + origin_task_runner_->PostTask( + FROM_HERE, base::Bind(&GenericURLRequestJob::MockResponse, + weak_factory_.GetWeakPtr(), + base::Passed(std::move(mock_response)))); + return; + } + + mock_response_ = std::move(mock_response); + + OnFetchCompleteExtractHeaders(request_->url(), + mock_response_->http_response_code, + mock_response_->response_data.data(), + mock_response_->response_data.size()); +} + } // namespace headless
diff --git a/headless/public/util/generic_url_request_job.h b/headless/public/util/generic_url_request_job.h index 909befa21..da6a4972 100644 --- a/headless/public/util/generic_url_request_job.h +++ b/headless/public/util/generic_url_request_job.h
@@ -25,10 +25,93 @@ class IOBuffer; } // namespace net +namespace content { +class ResourceRequestInfo; +} // namespace content + namespace headless { class URLRequestDispatcher; +// Wrapper around net::URLRequest with helpers to access select metadata. +class Request { + public: + virtual const net::URLRequest* GetURLRequest() const = 0; + + // The frame from which the request came from. + virtual int GetFrameTreeNodeId() const = 0; + + // The devtools agent host id for the page where the request came from. + virtual std::string GetDevToolsAgentHostId() const = 0; + + enum class ResourceType { + MAIN_FRAME = 0, + SUB_FRAME = 1, + STYLESHEET = 2, + SCRIPT = 3, + IMAGE = 4, + FONT_RESOURCE = 5, + SUB_RESOURCE = 6, + OBJECT = 7, + MEDIA = 8, + WORKER = 9, + SHARED_WORKER = 10, + PREFETCH = 11, + FAVICON = 12, + XHR = 13, + PING = 14, + SERVICE_WORKER = 15, + CSP_REPORT = 16, + PLUGIN_RESOURCE = 17, + LAST_TYPE + }; + + virtual ResourceType GetResourceType() const = 0; + + protected: + Request() {} + virtual ~Request() {} + + private: + DISALLOW_COPY_AND_ASSIGN(Request); +}; + +// Details of a pending request received by GenericURLRequestJob which must be +// either Allowed, Blocked, Modified or have it's response Mocked. +class PendingRequest { + public: + virtual const Request* GetRequest() const = 0; + + // Allows the request to proceed as normal. + virtual void AllowRequest() = 0; + + // Causes the request to fail with the specified |error|. + virtual void BlockRequest(net::Error error) = 0; + + // Allows the request to be completely re-written. + virtual void ModifyRequest( + const GURL& url, + const std::string& method, + const std::string& post_data, + const net::HttpRequestHeaders& request_headers) = 0; + + struct MockResponseData { + int http_response_code = 0; + std::string response_data; + }; + + // Instead of fetching the request, |mock_response| is returned instead. + virtual void MockResponse( + std::unique_ptr<MockResponseData> mock_response) = 0; + + protected: + PendingRequest() {} + virtual ~PendingRequest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(PendingRequest); +}; + // Intended for use in a protocol handler, this ManagedDispatchURLRequestJob has // the following features: // @@ -37,47 +120,30 @@ // fetcher is invoked. class HEADLESS_EXPORT GenericURLRequestJob : public ManagedDispatchURLRequestJob, - public URLFetcher::ResultListener { + public URLFetcher::ResultListener, + public PendingRequest, + public Request { public: - enum class RewriteResult { kAllow, kDeny, kFailure }; - using RewriteCallback = base::Callback< - void(RewriteResult result, const GURL& url, const std::string& method)>; - - struct HttpResponse { - GURL final_url; - int http_response_code; - - // The HTTP headers and response body. Note the lifetime of |response_data| - // is expected to outlive the GenericURLRequestJob. - const char* response_data; // NOT OWNED - size_t response_data_size; - }; - class Delegate { public: - // Allows the delegate to rewrite the URL for a given request. Return true - // to signal that the rewrite is in progress and |callback| will be called - // with the result, or false to indicate that no rewriting is necessary. - // Called on an arbitrary thread. |callback| can be called on any thread. - virtual bool BlockOrRewriteRequest(const GURL& url, - const std::string& devtools_id, - const std::string& method, - const std::string& referrer, - RewriteCallback callback) = 0; + // Notifies the delegate of an PendingRequest which must either be + // allowed, blocked, modifed or it's response mocked. Called on an arbitrary + // thread. + virtual void OnPendingRequest(PendingRequest* pending_request) = 0; - // Allows the delegate to synchronously fulfill a request with a reply. - // Called on an arbitrary thread. - virtual const HttpResponse* MaybeMatchResource( - const GURL& url, - const std::string& devtools_id, - const std::string& method, - const net::HttpRequestHeaders& request_headers) = 0; + // Notifies the delegate of any fetch failure. Called on an arbitrary + // thread. + virtual void OnResourceLoadFailed(const Request* request, + net::Error error) = 0; // Signals that a resource load has finished. Called on an arbitrary thread. - virtual void OnResourceLoadComplete(const GURL& final_url, - const std::string& devtools_id, - const std::string& mime_type, - int http_response_code) = 0; + virtual void OnResourceLoadComplete( + const Request* request, + const GURL& final_url, + int http_response_code, + scoped_refptr<net::HttpResponseHeaders> response_headers, + const char* body, + size_t body_size) = 0; protected: virtual ~Delegate() {} @@ -110,29 +176,40 @@ const char* body, size_t body_size) override; + protected: + // Request implementation: + const net::URLRequest* GetURLRequest() const override; + int GetFrameTreeNodeId() const override; + std::string GetDevToolsAgentHostId() const override; + ResourceType GetResourceType() const override; + + // PendingRequest implementation: + const Request* GetRequest() const override; + void AllowRequest() override; + void BlockRequest(net::Error error) override; + void ModifyRequest(const GURL& url, + const std::string& method, + const std::string& post_data, + const net::HttpRequestHeaders& request_headers) override; + void MockResponse(std::unique_ptr<MockResponseData> mock_response) override; + private: - static void OnRewriteResult( - base::WeakPtr<GenericURLRequestJob> weak_this, - const scoped_refptr<base::SingleThreadTaskRunner>& origin_task_runner, - RewriteResult result, - const GURL& url, - const std::string& method); - void OnRewriteResultOnOriginThread(RewriteResult result, - const GURL& url, - const std::string& method); void PrepareCookies(const GURL& rewritten_url, const std::string& method, - const url::Origin& site_for_cookies); + const url::Origin& site_for_cookies, + const base::Closure& done_callback); void OnCookiesAvailable(const GURL& rewritten_url, const std::string& method, + const base::Closure& done_callback, const net::CookieList& cookie_list); std::unique_ptr<URLFetcher> url_fetcher_; net::HttpRequestHeaders extra_request_headers_; scoped_refptr<net::HttpResponseHeaders> response_headers_; scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_; - std::string devtools_request_id_; + std::unique_ptr<MockResponseData> mock_response_; Delegate* delegate_; // Not owned. + const content::ResourceRequestInfo* request_resource_info_; // Not owned. const char* body_ = nullptr; // Not owned. int http_response_code_ = 0; size_t body_size_ = 0;
diff --git a/headless/public/util/generic_url_request_job_test.cc b/headless/public/util/generic_url_request_job_test.cc index 02e52cc0..b4aec67 100644 --- a/headless/public/util/generic_url_request_job_test.cc +++ b/headless/public/util/generic_url_request_job_test.cc
@@ -18,11 +18,15 @@ #include "headless/public/util/expedited_dispatcher.h" #include "headless/public/util/testing/generic_url_request_mocks.h" #include "headless/public/util/url_fetcher.h" +#include "net/base/elements_upload_data_stream.h" +#include "net/base/upload_bytes_element_reader.h" #include "net/http/http_response_headers.h" #include "net/url_request/url_request_job_factory_impl.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +using testing::_; + std::ostream& operator<<(std::ostream& os, const base::Value& value) { std::string json; base::JSONWriter::WriteWithOptions( @@ -41,21 +45,25 @@ namespace { +class MockDelegate : public MockGenericURLRequestJobDelegate { + public: + MOCK_METHOD2(OnResourceLoadFailed, + void(const Request* request, net::Error error)); +}; + class MockFetcher : public URLFetcher { public: MockFetcher(base::DictionaryValue* fetch_request, - const std::string& json_reply) - : fetch_reply_(base::JSONReader::Read(json_reply, base::JSON_PARSE_RFC)), - fetch_request_(fetch_request) { - CHECK(fetch_reply_) << "Invalid json: " << json_reply; - } + std::map<std::string, std::string>* json_fetch_reply_map) + : json_fetch_reply_map_(json_fetch_reply_map), + fetch_request_(fetch_request) {} ~MockFetcher() override {} void StartFetch(const GURL& url, const std::string& method, + const std::string& post_data, const net::HttpRequestHeaders& request_headers, - const std::string& devtools_request_id, ResultListener* result_listener) override { // Record the request. fetch_request_->SetString("url", url.spec()); @@ -65,10 +73,22 @@ headers->SetString(it.name(), it.value()); } fetch_request_->Set("headers", std::move(headers)); + if (!post_data.empty()) + fetch_request_->SetString("post_data", post_data); + + const auto find_it = json_fetch_reply_map_->find(url.spec()); + if (find_it == json_fetch_reply_map_->end()) { + result_listener->OnFetchStartError(net::ERR_ADDRESS_UNREACHABLE); + return; + } // Return the canned response. + std::unique_ptr<base::Value> fetch_reply( + base::JSONReader::Read(find_it->second, base::JSON_PARSE_RFC)); + CHECK(fetch_reply) << "Invalid json: " << find_it->second; + base::DictionaryValue* reply_dictionary; - ASSERT_TRUE(fetch_reply_->GetAsDictionary(&reply_dictionary)); + ASSERT_TRUE(fetch_reply->GetAsDictionary(&reply_dictionary)); std::string final_url; ASSERT_TRUE(reply_dictionary->GetString("url", &final_url)); int http_response_code; @@ -94,7 +114,7 @@ } private: - std::unique_ptr<base::Value> fetch_reply_; + std::map<std::string, std::string>* json_fetch_reply_map_; // NOT OWNED base::DictionaryValue* fetch_request_; // NOT OWNED std::string response_data_; // Here to ensure the required lifetime. }; @@ -102,13 +122,13 @@ class MockProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler { public: // Details of the fetch will be stored in |fetch_request|. - // The fetch response will be created from parsing |json_fetch_reply_|. + // The fetch response will be created from parsing |json_fetch_reply_map|. MockProtocolHandler(base::DictionaryValue* fetch_request, - std::string* json_fetch_reply, + std::map<std::string, std::string>* json_fetch_reply_map, URLRequestDispatcher* dispatcher, GenericURLRequestJob::Delegate* job_delegate) : fetch_request_(fetch_request), - json_fetch_reply_(json_fetch_reply), + json_fetch_reply_map_(json_fetch_reply_map), job_delegate_(job_delegate), dispatcher_(dispatcher) {} @@ -118,13 +138,13 @@ net::NetworkDelegate* network_delegate) const override { return new GenericURLRequestJob( request, network_delegate, dispatcher_, - base::MakeUnique<MockFetcher>(fetch_request_, *json_fetch_reply_), + base::MakeUnique<MockFetcher>(fetch_request_, json_fetch_reply_map_), job_delegate_); } private: base::DictionaryValue* fetch_request_; // NOT OWNED - std::string* json_fetch_reply_; // NOT OWNED + std::map<std::string, std::string>* json_fetch_reply_map_; // NOT OWNED GenericURLRequestJob::Delegate* job_delegate_; // NOT OWNED URLRequestDispatcher* dispatcher_; // NOT OWNED }; @@ -136,16 +156,16 @@ GenericURLRequestJobTest() : dispatcher_(message_loop_.task_runner()) { url_request_job_factory_.SetProtocolHandler( "https", base::WrapUnique(new MockProtocolHandler( - &fetch_request_, &json_fetch_reply_, &dispatcher_, + &fetch_request_, &json_fetch_reply_map_, &dispatcher_, &job_delegate_))); url_request_context_.set_job_factory(&url_request_job_factory_); url_request_context_.set_cookie_store(&cookie_store_); } - std::unique_ptr<net::URLRequest> CreateAndCompleteJob( + std::unique_ptr<net::URLRequest> CreateAndCompleteGetJob( const GURL& url, const std::string& json_reply) { - json_fetch_reply_ = json_reply; + json_fetch_reply_map_[url.spec()] = json_reply; std::unique_ptr<net::URLRequest> request(url_request_context_.CreateRequest( url, net::DEFAULT_PRIORITY, &request_delegate_)); @@ -164,17 +184,21 @@ MockURLRequestDelegate request_delegate_; base::DictionaryValue fetch_request_; // The request sent to MockFetcher. - std::string json_fetch_reply_; // The reply to be sent by MockFetcher. - MockGenericURLRequestJobDelegate job_delegate_; + std::map<std::string, std::string> + json_fetch_reply_map_; // Replies to be sent by MockFetcher. + MockDelegate job_delegate_; }; -TEST_F(GenericURLRequestJobTest, BasicRequestParams) { - // TODO(alexclarke): Lobby for raw string literals and use them here! - json_fetch_reply_ = - "{\"url\":\"https://example.com\"," - " \"http_response_code\":200," - " \"data\":\"Reply\"," - " \"headers\":{\"Content-Type\":\"text/plain\"}}"; +TEST_F(GenericURLRequestJobTest, BasicGetRequestParams) { + json_fetch_reply_map_["https://example.com/"] = R"( + { + "url": "https://example.com", + "http_response_code": 200, + "data": "Reply", + "headers": { + "Content-Type": "text/html; charset=UTF-8" + } + })"; std::unique_ptr<net::URLRequest> request(url_request_context_.CreateRequest( GURL("https://example.com"), net::DEFAULT_PRIORITY, &request_delegate_)); @@ -185,30 +209,79 @@ request->Start(); base::RunLoop().RunUntilIdle(); - std::string expected_request_json = - "{\"url\": \"https://example.com/\"," - " \"method\": \"GET\"," - " \"headers\": {" - " \"Accept\": \"text/plain\"," - " \"Cookie\": \"\"," - " \"Extra-Header\": \"Value\"," - " \"Referer\": \"https://referrer.example.com/\"," - " \"User-Agent\": \"TestBrowser\"" - " }" - "}"; + std::string expected_request_json = R"( + { + "url": "https://example.com/", + "method": "GET", + "headers": { + "Accept": "text/plain", + "Cookie": "", + "Extra-Header": "Value", + "Referer": "https://referrer.example.com/", + "User-Agent": "TestBrowser" + } + })"; + + EXPECT_THAT(fetch_request_, MatchesJson(expected_request_json)); +} + +TEST_F(GenericURLRequestJobTest, BasicPostRequestParams) { + json_fetch_reply_map_["https://example.com/"] = R"( + { + "url": "https://example.com", + "http_response_code": 200, + "data": "Reply", + "headers": { + "Content-Type": "text/html; charset=UTF-8" + } + })"; + + std::unique_ptr<net::URLRequest> request(url_request_context_.CreateRequest( + GURL("https://example.com"), net::DEFAULT_PRIORITY, &request_delegate_)); + request->SetReferrer("https://referrer.example.com"); + request->SetExtraRequestHeaderByName("Extra-Header", "Value", true); + request->SetExtraRequestHeaderByName("User-Agent", "TestBrowser", true); + request->SetExtraRequestHeaderByName("Accept", "text/plain", true); + request->set_method("POST"); + + std::string post_data = "lorem ipsom"; + request->set_upload(net::ElementsUploadDataStream::CreateWithReader( + base::MakeUnique<net::UploadBytesElementReader>(post_data.data(), + post_data.size()), + 0)); + request->Start(); + base::RunLoop().RunUntilIdle(); + + std::string expected_request_json = R"( + { + "url": "https://example.com/", + "method": "POST", + "post_data": "lorem ipsom", + "headers": { + "Accept": "text/plain", + "Cookie": "", + "Extra-Header": "Value", + "Referer": "https://referrer.example.com/", + "User-Agent": "TestBrowser" + } + })"; EXPECT_THAT(fetch_request_, MatchesJson(expected_request_json)); } TEST_F(GenericURLRequestJobTest, BasicRequestProperties) { - std::string reply = - "{\"url\":\"https://example.com\"," - " \"http_response_code\":200," - " \"data\":\"Reply\"," - " \"headers\":{\"Content-Type\":\"text/html; charset=UTF-8\"}}"; + std::string reply = R"( + { + "url": "https://example.com", + "http_response_code": 200, + "data": "Reply", + "headers": { + "Content-Type": "text/html; charset=UTF-8" + } + })"; std::unique_ptr<net::URLRequest> request( - CreateAndCompleteJob(GURL("https://example.com"), reply)); + CreateAndCompleteGetJob(GURL("https://example.com"), reply)); EXPECT_EQ(200, request->GetResponseCode()); @@ -227,14 +300,18 @@ } TEST_F(GenericURLRequestJobTest, BasicRequestContents) { - std::string reply = - "{\"url\":\"https://example.com\"," - " \"http_response_code\":200," - " \"data\":\"Reply\"," - " \"headers\":{\"Content-Type\":\"text/html; charset=UTF-8\"}}"; + std::string reply = R"( + { + "url": "https://example.com", + "http_response_code": 200, + "data": "Reply", + "headers": { + "Content-Type": "text/html; charset=UTF-8" + } + })"; std::unique_ptr<net::URLRequest> request( - CreateAndCompleteJob(GURL("https://example.com"), reply)); + CreateAndCompleteGetJob(GURL("https://example.com"), reply)); const int kBufferSize = 256; scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize)); @@ -249,14 +326,18 @@ } TEST_F(GenericURLRequestJobTest, ReadInParts) { - std::string reply = - "{\"url\":\"https://example.com\"," - " \"http_response_code\":200," - " \"data\":\"Reply\"," - " \"headers\":{\"Content-Type\":\"text/html; charset=UTF-8\"}}"; + std::string reply = R"( + { + "url": "https://example.com", + "http_response_code": 200, + "data": "Reply", + "headers": { + "Content-Type": "text/html; charset=UTF-8" + } + })"; std::unique_ptr<net::URLRequest> request( - CreateAndCompleteJob(GURL("https://example.com"), reply)); + CreateAndCompleteGetJob(GURL("https://example.com"), reply)); const int kBufferSize = 3; scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize)); @@ -332,41 +413,200 @@ /* http_only */ false, net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_DEFAULT)); - std::string reply = - "{\"url\":\"https://example.com\"," - " \"http_response_code\":200," - " \"data\":\"Reply\"," - " \"headers\":{\"Content-Type\":\"text/html; charset=UTF-8\"}}"; + std::string reply = R"( + { + "url": "https://example.com", + "http_response_code": 200, + "data": "Reply", + "headers": { + "Content-Type": "text/html; charset=UTF-8" + } + })"; std::unique_ptr<net::URLRequest> request( - CreateAndCompleteJob(GURL("https://example.com"), reply)); + CreateAndCompleteGetJob(GURL("https://example.com"), reply)); - std::string expected_request_json = - "{\"url\": \"https://example.com/\"," - " \"method\": \"GET\"," - " \"headers\": {" - " \"Cookie\": \"basic_cookie=1; secure_cookie=2; http_only_cookie=3\"," - " \"Referer\": \"\"" - " }" - "}"; + std::string expected_request_json = R"( + { + "url": "https://example.com/", + "method": "GET", + "headers": { + "Cookie": "basic_cookie=1; secure_cookie=2; http_only_cookie=3", + "Referer": "" + } + })"; EXPECT_THAT(fetch_request_, MatchesJson(expected_request_json)); } TEST_F(GenericURLRequestJobTest, DelegateBlocksLoading) { - std::string reply = - "{\"url\":\"https://example.com\"," - " \"http_response_code\":200," - " \"data\":\"Reply\"," - " \"headers\":{\"Content-Type\":\"text/html; charset=UTF-8\"}}"; + std::string reply = R"( + { + "url": "https://example.com", + "http_response_code": 200, + "data": "Reply", + "headers": { + "Content-Type": "text/html; charset=UTF-8" + } + })"; - job_delegate_.SetShouldBlock(true); + job_delegate_.SetPolicy(base::Bind([](PendingRequest* pending_request) { + pending_request->BlockRequest(net::ERR_FILE_NOT_FOUND); + })); std::unique_ptr<net::URLRequest> request( - CreateAndCompleteJob(GURL("https://example.com"), reply)); + CreateAndCompleteGetJob(GURL("https://example.com"), reply)); EXPECT_EQ(net::URLRequestStatus::FAILED, request->status().status()); EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request->status().error()); } +TEST_F(GenericURLRequestJobTest, DelegateModifiesRequest) { + json_fetch_reply_map_["https://example.com/"] = R"( + { + "url": "https://example.com", + "http_response_code": 200, + "data": "Welcome to example.com", + "headers": { + "Content-Type": "text/html; charset=UTF-8" + } + })"; + + json_fetch_reply_map_["https://othersite.com/"] = R"( + { + "url": "https://example.com", + "http_response_code": 200, + "data": "Welcome to othersite.com", + "headers": { + "Content-Type": "text/html; charset=UTF-8" + } + })"; + + // Turn the GET into a POST to a different site. + job_delegate_.SetPolicy(base::Bind([](PendingRequest* pending_request) { + net::HttpRequestHeaders headers; + headers.SetHeader("TestHeader", "Hello"); + pending_request->ModifyRequest(GURL("https://othersite.com"), "POST", + "Some post data!", headers); + })); + + std::unique_ptr<net::URLRequest> request(url_request_context_.CreateRequest( + GURL("https://example.com"), net::DEFAULT_PRIORITY, &request_delegate_)); + request->Start(); + base::RunLoop().RunUntilIdle(); + + std::string expected_request_json = R"( + { + "url": "https://othersite.com/", + "method": "POST", + "post_data": "Some post data!", + "headers": { + "TestHeader": "Hello" + } + })"; + + EXPECT_THAT(fetch_request_, MatchesJson(expected_request_json)); + + EXPECT_EQ(200, request->GetResponseCode()); + // The modification should not be visible to the URlRequest. + EXPECT_EQ("https://example.com/", request->url().spec()); + EXPECT_EQ("GET", request->method()); + + const int kBufferSize = 256; + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize)); + int bytes_read; + EXPECT_TRUE(request->Read(buffer.get(), kBufferSize, &bytes_read)); + EXPECT_EQ(24, bytes_read); + EXPECT_EQ("Welcome to othersite.com", + std::string(buffer->data(), bytes_read)); +} + +TEST_F(GenericURLRequestJobTest, DelegateMocks404Response) { + std::string reply = R"( + { + "url": "https://example.com", + "http_response_code": 200, + "data": "Reply", + "headers": { + "Content-Type": "text/html; charset=UTF-8" + } + })"; + + job_delegate_.SetPolicy(base::Bind([](PendingRequest* pending_request) { + std::unique_ptr<GenericURLRequestJob::MockResponseData> mock_response_data( + new GenericURLRequestJob::MockResponseData()); + mock_response_data->http_response_code = 404; + mock_response_data->response_data = "HTTP/1.1 404 Not Found\r\n\r\n"; + pending_request->MockResponse(std::move(mock_response_data)); + })); + + std::unique_ptr<net::URLRequest> request( + CreateAndCompleteGetJob(GURL("https://example.com"), reply)); + + EXPECT_EQ(404, request->GetResponseCode()); +} + +TEST_F(GenericURLRequestJobTest, DelegateMocks302Response) { + job_delegate_.SetPolicy(base::Bind([](PendingRequest* pending_request) { + if (pending_request->GetRequest()->GetURLRequest()->url().spec() == + "https://example.com/") { + std::unique_ptr<GenericURLRequestJob::MockResponseData> + mock_response_data(new GenericURLRequestJob::MockResponseData()); + mock_response_data->http_response_code = 302; + mock_response_data->response_data = + "HTTP/1.1 302 Found\r\n" + "Location: https://foo.com/\r\n\r\n"; + pending_request->MockResponse(std::move(mock_response_data)); + } else { + pending_request->AllowRequest(); + } + })); + + json_fetch_reply_map_["https://example.com/"] = R"( + { + "url": "https://example.com", + "http_response_code": 200, + "data": "Welcome to example.com", + "headers": { + "Content-Type": "text/html; charset=UTF-8" + } + })"; + + json_fetch_reply_map_["https://foo.com/"] = R"( + { + "url": "https://example.com", + "http_response_code": 200, + "data": "Welcome to foo.com", + "headers": { + "Content-Type": "text/html; charset=UTF-8" + } + })"; + + std::unique_ptr<net::URLRequest> request(url_request_context_.CreateRequest( + GURL("https://example.com"), net::DEFAULT_PRIORITY, &request_delegate_)); + request->Start(); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(200, request->GetResponseCode()); + EXPECT_EQ("https://foo.com/", request->url().spec()); + + const int kBufferSize = 256; + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize)); + int bytes_read; + EXPECT_TRUE(request->Read(buffer.get(), kBufferSize, &bytes_read)); + EXPECT_EQ(18, bytes_read); + EXPECT_EQ("Welcome to foo.com", std::string(buffer->data(), bytes_read)); +} + +TEST_F(GenericURLRequestJobTest, OnResourceLoadFailed) { + EXPECT_CALL(job_delegate_, + OnResourceLoadFailed(_, net::ERR_ADDRESS_UNREACHABLE)); + + std::unique_ptr<net::URLRequest> request(url_request_context_.CreateRequest( + GURL("https://i-dont-exist.com"), net::DEFAULT_PRIORITY, + &request_delegate_)); + request->Start(); + base::RunLoop().RunUntilIdle(); +} + } // namespace headless
diff --git a/headless/public/util/http_url_fetcher.cc b/headless/public/util/http_url_fetcher.cc index a3171b3f..ac40607 100644 --- a/headless/public/util/http_url_fetcher.cc +++ b/headless/public/util/http_url_fetcher.cc
@@ -4,7 +4,9 @@ #include "headless/public/util/http_url_fetcher.h" +#include "net/base/elements_upload_data_stream.h" #include "net/base/io_buffer.h" +#include "net/base/upload_bytes_element_reader.h" #include "net/cert/cert_status_flags.h" #include "net/http/http_response_headers.h" #include "net/url_request/url_request.h" @@ -16,6 +18,7 @@ public: Delegate(const GURL& rewritten_url, const std::string& method, + const std::string& post_data, const net::HttpRequestHeaders& request_headers, const net::URLRequestContext* url_request_context, ResultListener* result_listener); @@ -56,6 +59,7 @@ HttpURLFetcher::Delegate::Delegate( const GURL& rewritten_url, const std::string& method, + const std::string& post_data, const net::HttpRequestHeaders& request_headers, const net::URLRequestContext* url_request_context, ResultListener* result_listener) @@ -66,6 +70,14 @@ this)), result_listener_(result_listener) { request_->set_method(method); + + if (!post_data.empty()) { + request_->set_upload(net::ElementsUploadDataStream::CreateWithReader( + base::MakeUnique<net::UploadBytesElementReader>(post_data.data(), + post_data.size()), + 0)); + } + request_->SetExtraRequestHeaders(request_headers); request_->Start(); } @@ -183,11 +195,12 @@ void HttpURLFetcher::StartFetch(const GURL& rewritten_url, const std::string& method, + const std::string& post_data, const net::HttpRequestHeaders& request_headers, - const std::string& devtools_request_id, ResultListener* result_listener) { - delegate_.reset(new Delegate(rewritten_url, method, request_headers, - url_request_context_, result_listener)); + delegate_.reset(new Delegate(rewritten_url, method, post_data, + request_headers, url_request_context_, + result_listener)); } } // namespace headless
diff --git a/headless/public/util/http_url_fetcher.h b/headless/public/util/http_url_fetcher.h index 5049b4ec..c69d9fb2 100644 --- a/headless/public/util/http_url_fetcher.h +++ b/headless/public/util/http_url_fetcher.h
@@ -24,8 +24,8 @@ // URLFetcher implementation: void StartFetch(const GURL& rewritten_url, const std::string& method, + const std::string& post_data, const net::HttpRequestHeaders& request_headers, - const std::string& devtools_request_id, ResultListener* result_listener) override; private:
diff --git a/headless/public/util/protocol_handler_request_id_browsertest.cc b/headless/public/util/protocol_handler_request_id_browsertest.cc deleted file mode 100644 index 68a34e25..0000000 --- a/headless/public/util/protocol_handler_request_id_browsertest.cc +++ /dev/null
@@ -1,234 +0,0 @@ -// Copyright 2017 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/run_loop.h" -#include "content/public/common/browser_side_navigation_policy.h" -#include "content/public/test/browser_test.h" -#include "headless/public/devtools/domains/network.h" -#include "headless/public/devtools/domains/page.h" -#include "headless/public/headless_devtools_client.h" -#include "headless/public/util/expedited_dispatcher.h" -#include "headless/public/util/generic_url_request_job.h" -#include "headless/public/util/url_fetcher.h" -#include "headless/test/headless_browser_test.h" -#include "net/url_request/url_request_job_factory.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "url/gurl.h" - -using testing::ContainerEq; - -namespace headless { - -namespace { -// Keep in sync with X_DevTools_Request_Id defined in HTTPNames.json5. -const char kDevtoolsRequestId[] = "X-DevTools-Request-Id"; -} // namespace - -namespace { -class RequestIdCorrelationProtocolHandler - : public net::URLRequestJobFactory::ProtocolHandler { - public: - explicit RequestIdCorrelationProtocolHandler( - scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner) - : test_delegate_(new TestDelegate(this)), - dispatcher_(new ExpeditedDispatcher(io_thread_task_runner)) {} - - ~RequestIdCorrelationProtocolHandler() override {} - - struct Response { - Response() {} - Response(const std::string& body, const std::string& mime_type) - : data("HTTP/1.1 200 OK\r\nContent-Type: " + mime_type + "\r\n\r\n" + - body) {} - - std::string data; - }; - - void InsertResponse(const std::string& url, const Response& response) { - response_map_[url] = response; - } - - const Response* GetResponse(const std::string& url) const { - std::map<std::string, Response>::const_iterator find_it = - response_map_.find(url); - if (find_it == response_map_.end()) - return nullptr; - return &find_it->second; - } - - class MockURLFetcher : public URLFetcher { - public: - explicit MockURLFetcher( - const RequestIdCorrelationProtocolHandler* protocol_handler) - : protocol_handler_(protocol_handler) {} - ~MockURLFetcher() override {} - - // URLFetcher implementation: - void StartFetch(const GURL& url, - const std::string& method, - const net::HttpRequestHeaders& request_headers, - const std::string& devtools_request_id, - ResultListener* result_listener) override { - const Response* response = protocol_handler_->GetResponse(url.spec()); - if (!response) - result_listener->OnFetchStartError(net::ERR_FILE_NOT_FOUND); - - // The header used for correlation should not be sent to the fetcher. - EXPECT_FALSE(request_headers.HasHeader(kDevtoolsRequestId)); - - result_listener->OnFetchCompleteExtractHeaders( - url, 200, response->data.c_str(), response->data.size()); - } - - private: - const RequestIdCorrelationProtocolHandler* protocol_handler_; - - DISALLOW_COPY_AND_ASSIGN(MockURLFetcher); - }; - - class TestDelegate : public GenericURLRequestJob::Delegate { - public: - explicit TestDelegate(RequestIdCorrelationProtocolHandler* protocol_handler) - : protocol_handler_(protocol_handler) {} - ~TestDelegate() override {} - - // GenericURLRequestJob::Delegate implementation: - bool BlockOrRewriteRequest( - const GURL& url, - const std::string& devtools_id, - const std::string& method, - const std::string& referrer, - GenericURLRequestJob::RewriteCallback callback) override { - protocol_handler_->url_to_devtools_id_[url.spec()] = devtools_id; - return false; - } - - const GenericURLRequestJob::HttpResponse* MaybeMatchResource( - const GURL& url, - const std::string& devtools_id, - const std::string& method, - const net::HttpRequestHeaders& request_headers) override { - return nullptr; - } - - void OnResourceLoadComplete(const GURL& final_url, - const std::string& devtools_id, - const std::string& mime_type, - int http_response_code) override {} - - private: - RequestIdCorrelationProtocolHandler* protocol_handler_; - - DISALLOW_COPY_AND_ASSIGN(TestDelegate); - }; - - // net::URLRequestJobFactory::ProtocolHandler implementation:: - net::URLRequestJob* MaybeCreateJob( - net::URLRequest* request, - net::NetworkDelegate* network_delegate) const override { - return new GenericURLRequestJob( - request, network_delegate, dispatcher_.get(), - base::MakeUnique<MockURLFetcher>(this), test_delegate_.get()); - } - - std::map<std::string, std::string> url_to_devtools_id_; - - private: - std::unique_ptr<TestDelegate> test_delegate_; - std::unique_ptr<ExpeditedDispatcher> dispatcher_; - std::map<std::string, Response> response_map_; - - DISALLOW_COPY_AND_ASSIGN(RequestIdCorrelationProtocolHandler); -}; - -const char* kIndexHtml = R"( -<html> -<head> -<link rel="stylesheet" type="text/css" href="style1.css"> -<link rel="stylesheet" type="text/css" href="style2.css"> -</head> -<body>Hello. -</body> -</html>)"; - -const char* kStyle1 = R"( -.border { - border: 1px solid #000; -})"; - -const char* kStyle2 = R"( -.border { - border: 2px solid #fff; -})"; - -} // namespace - -class ProtocolHandlerRequestIdCorrelationTest - : public HeadlessAsyncDevTooledBrowserTest, - public network::Observer, - public page::Observer { - public: - void RunDevTooledTest() override { - if (content::IsBrowserSideNavigationEnabled()) { - // TODO: get this working with PlzNavigate. - // See discussion on https://codereview.chromium.org/2695923010/ - FinishAsynchronousTest(); - return; - } - - EXPECT_TRUE(embedded_test_server()->Start()); - devtools_client_->GetPage()->AddObserver(this); - devtools_client_->GetPage()->Enable(); - - base::RunLoop run_loop; - devtools_client_->GetNetwork()->AddObserver(this); - devtools_client_->GetNetwork()->Enable(run_loop.QuitClosure()); - base::MessageLoop::ScopedNestableTaskAllower nest_loop( - base::MessageLoop::current()); - run_loop.Run(); - - devtools_client_->GetPage()->Navigate("http://foo.com/index.html"); - } - - ProtocolHandlerMap GetProtocolHandlers() override { - ProtocolHandlerMap protocol_handlers; - std::unique_ptr<RequestIdCorrelationProtocolHandler> http_handler( - new RequestIdCorrelationProtocolHandler(browser()->BrowserIOThread())); - http_handler_ = http_handler.get(); - http_handler_->InsertResponse("http://foo.com/index.html", - {kIndexHtml, "text/html"}); - http_handler_->InsertResponse("http://foo.com/style1.css", - {kStyle1, "text/css"}); - http_handler_->InsertResponse("http://foo.com/style2.css", - {kStyle2, "text/css"}); - protocol_handlers[url::kHttpScheme] = std::move(http_handler); - return protocol_handlers; - } - - // network::Observer implementation: - void OnRequestWillBeSent( - const network::RequestWillBeSentParams& params) override { - url_to_devtools_id_[params.GetRequest()->GetUrl()] = params.GetRequestId(); - EXPECT_FALSE(params.GetRequest()->GetHeaders()->HasKey(kDevtoolsRequestId)); - } - - // page::Observer implementation: - void OnLoadEventFired(const page::LoadEventFiredParams& params) override { - // Make sure that our protocol handler saw the same url : devtools ids as - // our OnRequestWillBeSent event listener did. - EXPECT_THAT(url_to_devtools_id_, - ContainerEq(http_handler_->url_to_devtools_id_)); - EXPECT_EQ(3u, url_to_devtools_id_.size()); - FinishAsynchronousTest(); - } - - private: - std::map<std::string, std::string> url_to_devtools_id_; - RequestIdCorrelationProtocolHandler* http_handler_; // NOT OWNED -}; - -HEADLESS_ASYNC_DEVTOOLED_TEST_F(ProtocolHandlerRequestIdCorrelationTest); - -} // namespace headless
diff --git a/headless/public/util/testing/generic_url_request_mocks.cc b/headless/public/util/testing/generic_url_request_mocks.cc index 3d5e682..4a7d37de 100644 --- a/headless/public/util/testing/generic_url_request_mocks.cc +++ b/headless/public/util/testing/generic_url_request_mocks.cc
@@ -15,45 +15,43 @@ // MockGenericURLRequestJobDelegate MockGenericURLRequestJobDelegate::MockGenericURLRequestJobDelegate() - : should_block_(false), - main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()) {} + : main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()) {} + MockGenericURLRequestJobDelegate::~MockGenericURLRequestJobDelegate() {} -bool MockGenericURLRequestJobDelegate::BlockOrRewriteRequest( - const GURL& url, - const std::string& devtools_id, - const std::string& method, - const std::string& referrer, - GenericURLRequestJob::RewriteCallback callback) { - if (should_block_) { - // Simulate the client acknowledging the callback from a different thread. - main_thread_task_runner_->PostTask( - FROM_HERE, base::Bind( - [](GenericURLRequestJob::RewriteCallback callback, - std::string method) { - callback.Run( - GenericURLRequestJob::RewriteResult::kDeny, GURL(), - method); - }, - callback, method)); - } - return should_block_; +// GenericURLRequestJob::Delegate methods: +void MockGenericURLRequestJobDelegate::OnPendingRequest( + PendingRequest* pending_request) { + // Simulate the client acknowledging the callback from a different thread. + main_thread_task_runner_->PostTask( + FROM_HERE, base::Bind(&MockGenericURLRequestJobDelegate::ApplyPolicy, + base::Unretained(this), pending_request)); } -const GenericURLRequestJob::HttpResponse* -MockGenericURLRequestJobDelegate::MaybeMatchResource( - const GURL& url, - const std::string& devtools_id, - const std::string& method, - const net::HttpRequestHeaders& request_headers) { - return nullptr; +void MockGenericURLRequestJobDelegate::SetPolicy(Policy policy) { + policy_ = policy; } +void MockGenericURLRequestJobDelegate::ApplyPolicy( + PendingRequest* pending_request) { + if (policy_.is_null()) { + pending_request->AllowRequest(); + } else { + policy_.Run(pending_request); + } +} + +void MockGenericURLRequestJobDelegate::OnResourceLoadFailed( + const Request* request, + net::Error error) {} + void MockGenericURLRequestJobDelegate::OnResourceLoadComplete( + const Request* request, const GURL& final_url, - const std::string& devtools_id, - const std::string& mime_type, - int http_response_code) {} + int http_response_code, + scoped_refptr<net::HttpResponseHeaders> response_headers, + const char* body, + size_t body_size) {} // MockCookieStore MockCookieStore::MockCookieStore() {}
diff --git a/headless/public/util/testing/generic_url_request_mocks.h b/headless/public/util/testing/generic_url_request_mocks.h index 50c1d60..218c3ce 100644 --- a/headless/public/util/testing/generic_url_request_mocks.h +++ b/headless/public/util/testing/generic_url_request_mocks.h
@@ -25,28 +25,25 @@ MockGenericURLRequestJobDelegate(); ~MockGenericURLRequestJobDelegate() override; - bool BlockOrRewriteRequest( - const GURL& url, - const std::string& devtools_id, - const std::string& method, - const std::string& referrer, - GenericURLRequestJob::RewriteCallback callback) override; + // GenericURLRequestJob::Delegate methods: + void OnPendingRequest(PendingRequest* pending_request) override; + void OnResourceLoadFailed(const Request* request, net::Error error) override; + void OnResourceLoadComplete( + const Request* request, + const GURL& final_url, + int http_response_code, + scoped_refptr<net::HttpResponseHeaders> response_headers, + const char* body, + size_t body_size) override; - const GenericURLRequestJob::HttpResponse* MaybeMatchResource( - const GURL& url, - const std::string& devtools_id, - const std::string& method, - const net::HttpRequestHeaders& request_headers) override; + using Policy = base::Callback<void(PendingRequest* pending_request)>; - void OnResourceLoadComplete(const GURL& final_url, - const std::string& devtools_id, - const std::string& mime_type, - int http_response_code) override; - - void SetShouldBlock(bool should_block) { should_block_ = should_block; } + void SetPolicy(Policy policy); private: - bool should_block_; + void ApplyPolicy(PendingRequest* pending_request); + + Policy policy_; scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_; DISALLOW_COPY_AND_ASSIGN(MockGenericURLRequestJobDelegate);
diff --git a/headless/public/util/url_fetcher.cc b/headless/public/util/url_fetcher.cc index 86fd3b3..8d8d33f 100644 --- a/headless/public/util/url_fetcher.cc +++ b/headless/public/util/url_fetcher.cc
@@ -37,17 +37,4 @@ response_data_size - read_offset); } -void URLFetcher::StartFetch(const GURL& rewritten_url, - const std::string& method, - const net::HttpRequestHeaders& request_headers, - const std::string& devtools_request_id, - ResultListener* result_listener) { - StartFetch(rewritten_url, method, request_headers, result_listener); -} - -void URLFetcher::StartFetch(const GURL& rewritten_url, - const std::string& method, - const net::HttpRequestHeaders& request_headers, - ResultListener* result_listener) {} - } // namespace headless
diff --git a/headless/public/util/url_fetcher.h b/headless/public/util/url_fetcher.h index 41bf3fa..df0cc0ff 100644 --- a/headless/public/util/url_fetcher.h +++ b/headless/public/util/url_fetcher.h
@@ -60,17 +60,11 @@ DISALLOW_COPY_AND_ASSIGN(ResultListener); }; - // Instructs the sub-class to fetch the resource. - virtual void StartFetch(const GURL& rewritten_url, + virtual void StartFetch(const GURL& url, const std::string& method, + const std::string& post_data, const net::HttpRequestHeaders& request_headers, - const std::string& devtools_request_id, - ResultListener* result_listener); - // TODO(alexclarke): Make the above pure virtual and remove this. - virtual void StartFetch(const GURL& rewritten_url, - const std::string& method, - const net::HttpRequestHeaders& request_headers, - ResultListener* result_listener); + ResultListener* result_listener) = 0; private: DISALLOW_COPY_AND_ASSIGN(URLFetcher);
diff --git a/ios/chrome/widget_extension/BUILD.gn b/ios/chrome/widget_extension/BUILD.gn index 7fbc32a..31fed23e 100644 --- a/ios/chrome/widget_extension/BUILD.gn +++ b/ios/chrome/widget_extension/BUILD.gn
@@ -29,7 +29,7 @@ deps = [ "//base", - "//base:i18n", + "//components/open_from_clipboard:open_from_clipboard_impl", "//components/prefs", "//components/variations", "//components/version_info", @@ -41,7 +41,6 @@ "//ios/third_party/material_components_ios", "//net", "//ui/base", - "//url", ] libs = [
diff --git a/ios/chrome/widget_extension/DEPS b/ios/chrome/widget_extension/DEPS new file mode 100644 index 0000000..5349816 --- /dev/null +++ b/ios/chrome/widget_extension/DEPS
@@ -0,0 +1,4 @@ +include_rules = [ + "+components/open_from_clipboard", + "-url", +]
diff --git a/ios/chrome/widget_extension/widget_view.h b/ios/chrome/widget_extension/widget_view.h index 9e2ff38..6b6bd57 100644 --- a/ios/chrome/widget_extension/widget_view.h +++ b/ios/chrome/widget_extension/widget_view.h
@@ -11,8 +11,16 @@ // view. @protocol WidgetViewActionTarget -// Called when the user taps the fake omnibox. -- (void)openApp:(id)sender; +// Called when the user taps the Search button. +- (void)openSearch:(id)sender; +// Called when the user taps the Incognito Search button. +- (void)openIncognito:(id)sender; +// Called when the user taps the Voice Search button. +- (void)openVoice:(id)sender; +// Called when the user taps the QR Code button. +- (void)openQRCode:(id)sender; +// Called when the user taps the Open Copied URL section. +- (void)openCopiedURL:(id)sender; @end @@ -27,6 +35,9 @@ - (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE; - (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE; +// Updates the copied URL. +- (void)updateCopiedURL:(NSString*)copiedURL; + @end #endif // IOS_CHROME_WIDGET_EXTENSION_WIDGET_VIEW_H_
diff --git a/ios/chrome/widget_extension/widget_view.mm b/ios/chrome/widget_extension/widget_view.mm index d746fd0..d078fe0 100644 --- a/ios/chrome/widget_extension/widget_view.mm +++ b/ios/chrome/widget_extension/widget_view.mm
@@ -25,6 +25,8 @@ __weak id<WidgetViewActionTarget> _target; } +@property(nonatomic, copy) NSString* copiedURL; +@property(nonatomic, strong) UILabel* copiedURLLabel; @property(nonatomic, weak) UIView* cursor; // Creates and adds a fake omnibox with blinking cursor to the view and sets the @@ -35,6 +37,9 @@ @implementation WidgetView +@synthesize copiedURL = _copiedURL; +@synthesize copiedURLLabel = _copiedURLLabel; + @synthesize cursor = _cursor; - (instancetype)initWithActionTarget:(id<WidgetViewActionTarget>)target { @@ -52,7 +57,7 @@ UIGestureRecognizer* tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:_target - action:@selector(openApp:)]; + action:@selector(openSearch:)]; [fakebox addGestureRecognizer:tapRecognizer]; [self addSubview:fakebox]; @@ -93,4 +98,9 @@ completion:nil]; } +- (void)updateCopiedURL:(NSString*)copiedURL { + self.copiedURL = copiedURL; + self.copiedURLLabel.text = copiedURL; +} + @end
diff --git a/ios/chrome/widget_extension/widget_view_controller.h b/ios/chrome/widget_extension/widget_view_controller.h index 57cb0af..6026622 100644 --- a/ios/chrome/widget_extension/widget_view_controller.h +++ b/ios/chrome/widget_extension/widget_view_controller.h
@@ -5,9 +5,10 @@ #ifndef IOS_CHROME_WIDGET_EXTENSION_WIDGET_VIEW_CONTROLLER_H_ #define IOS_CHROME_WIDGET_EXTENSION_WIDGET_VIEW_CONTROLLER_H_ +#import <NotificationCenter/NotificationCenter.h> #import <UIKit/UIKit.h> -@interface WidgetViewController : UIViewController +@interface WidgetViewController : UIViewController<NCWidgetProviding> @end
diff --git a/ios/chrome/widget_extension/widget_view_controller.mm b/ios/chrome/widget_extension/widget_view_controller.mm index aa93999c..b68b97a 100644 --- a/ios/chrome/widget_extension/widget_view_controller.mm +++ b/ios/chrome/widget_extension/widget_view_controller.mm
@@ -6,25 +6,61 @@ #import <NotificationCenter/NotificationCenter.h> +#include "base/ios/ios_util.h" #include "base/mac/foundation_util.h" #include "base/strings/sys_string_conversions.h" +#include "components/open_from_clipboard/clipboard_recent_content_impl_ios.h" #include "ios/chrome/common/app_group/app_group_constants.h" -#include "ios/chrome/common/x_callback_url.h" #import "ios/chrome/widget_extension/widget_view.h" -#import "net/base/mac/url_conversions.h" -#include "url/gurl.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif +namespace { +// Using GURL in the extension is not wanted as it includes ICU which makes the +// extension binary much larger; therefore, ios/chrome/common/x_callback_url.h +// cannot be used. This class makes a very basic use of x-callback-url, so no +// full implementation is required. +NSString* const kXCallbackURLHost = @"x-callback-url"; +} // namespace + @interface WidgetViewController ()<WidgetViewActionTarget> @property(nonatomic, weak) WidgetView* widgetView; +@property(nonatomic, strong) NSURL* copiedURL; +@property(nonatomic, strong) + ClipboardRecentContentImplIOS* clipboardRecentContent; + +// Updates the widget with latest data from the clipboard. Returns whether any +// visual updates occured. +- (BOOL)updateWidget; +// Opens the main application with the given |command|. +- (void)openAppWithCommand:(NSString*)command; +// Opens the main application with the given |command| and |parameter|. +- (void)openAppWithCommand:(NSString*)command parameter:(NSString*)parameter; +// Returns the dictionary of commands to pass via user defaults to open the main +// application for a given |command| and |parameter|. ++ (NSDictionary*)dictForCommand:(NSString*)command + parameter:(NSString*)parameter; + @end @implementation WidgetViewController @synthesize widgetView = _widgetView; +@synthesize copiedURL = _copiedURL; +@synthesize clipboardRecentContent = _clipboardRecentContent; + +- (instancetype)init { + self = [super init]; + if (self) { + _clipboardRecentContent = [[ClipboardRecentContentImplIOS alloc] + initWithAuthorizedSchemes:[NSSet setWithObjects:@"http", @"https", nil] + userDefaults:app_group::GetGroupUserDefaults() + delegate:nil]; + } + return self; +} #pragma mark - UIViewController @@ -37,25 +73,106 @@ self.widgetView = widgetView; [self.view addSubview:self.widgetView]; - [self.widgetView setTranslatesAutoresizingMaskIntoConstraints:NO]; + if (base::ios::IsRunningOnIOS10OrLater()) { + self.extensionContext.widgetLargestAvailableDisplayMode = + NCWidgetDisplayModeExpanded; + } + + self.widgetView.translatesAutoresizingMaskIntoConstraints = NO; + + NSLayoutConstraint* heightAnchor = [self.widgetView.heightAnchor + constraintEqualToAnchor:self.view.heightAnchor]; + heightAnchor.priority = 900; + [NSLayoutConstraint activateConstraints:@[ [self.widgetView.leadingAnchor - constraintEqualToAnchor:[self.view leadingAnchor]], + constraintEqualToAnchor:self.view.leadingAnchor], + [self.widgetView.widthAnchor constraintEqualToAnchor:self.view.widthAnchor], [self.widgetView.trailingAnchor - constraintEqualToAnchor:[self.view trailingAnchor]], - [self.widgetView.heightAnchor - constraintEqualToAnchor:[self.view heightAnchor]], - [self.widgetView.widthAnchor - constraintEqualToAnchor:[self.view widthAnchor]] + constraintEqualToAnchor:self.view.trailingAnchor], + heightAnchor, + [self.widgetView.topAnchor constraintEqualToAnchor:self.view.topAnchor], ]]; } -- (void)openApp:(id)sender { +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + [self updateWidget]; +} + +- (void)widgetPerformUpdateWithCompletionHandler: + (void (^)(NCUpdateResult))completionHandler { + completionHandler([self updateWidget] ? NCUpdateResultNewData + : NCUpdateResultNoData); +} + +- (BOOL)updateWidget { + NSURL* url = [_clipboardRecentContent recentURLFromClipboard]; + + if (![url isEqual:self.copiedURL]) { + self.copiedURL = url; + [self.widgetView updateCopiedURL:self.copiedURL.absoluteString]; + return YES; + } + return NO; +} + +#pragma mark - NCWidgetProviding + +- (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode + withMaximumSize:(CGSize)maxSize { + CGSize fittingSize = [self.widgetView + systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; + if (fittingSize.height > maxSize.height) { + self.preferredContentSize = maxSize; + } else { + self.preferredContentSize = fittingSize; + } +} + +#pragma mark - WidgetViewActionTarget + +- (void)openSearch:(id)sender { + [self openAppWithCommand:base::SysUTF8ToNSString( + app_group::kChromeAppGroupFocusOmniboxCommand)]; +} + +- (void)openIncognito:(id)sender { + [self + openAppWithCommand:base::SysUTF8ToNSString( + app_group::kChromeAppGroupIncognitoSearchCommand)]; +} + +- (void)openVoice:(id)sender { + [self openAppWithCommand:base::SysUTF8ToNSString( + app_group::kChromeAppGroupVoiceSearchCommand)]; +} + +- (void)openQRCode:(id)sender { + [self openAppWithCommand:base::SysUTF8ToNSString( + app_group::kChromeAppGroupQRScannerCommand)]; +} + +- (void)openCopiedURL:(id)sender { + DCHECK(self.copiedURL); + [self openAppWithCommand:base::SysUTF8ToNSString( + app_group::kChromeAppGroupOpenURLCommand) + parameter:self.copiedURL.absoluteString]; +} + +#pragma mark - internal + +- (void)openAppWithCommand:(NSString*)command { + return [self openAppWithCommand:command parameter:nil]; +} + +- (void)openAppWithCommand:(NSString*)command parameter:(NSString*)parameter { NSUserDefaults* sharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:app_group::ApplicationGroup()]; NSString* defaultsKey = base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandPreference); - [sharedDefaults setObject:[WidgetViewController commandDict] + [sharedDefaults setObject:[WidgetViewController dictForCommand:command + parameter:parameter] forKey:defaultsKey]; [sharedDefaults synchronize]; @@ -63,22 +180,37 @@ objectForInfoDictionaryKey:@"KSChannelChromeScheme"]); if (!scheme) return; - const GURL openURL = - CreateXCallbackURL(base::SysNSStringToUTF8(scheme), - app_group::kChromeAppGroupXCallbackCommand); - [self.extensionContext openURL:net::NSURLWithGURL(openURL) - completionHandler:nil]; + + NSURLComponents* urlComponents = [NSURLComponents new]; + urlComponents.scheme = scheme; + urlComponents.host = kXCallbackURLHost; + urlComponents.path = [NSString + stringWithFormat:@"/%@", base::SysUTF8ToNSString( + app_group::kChromeAppGroupXCallbackCommand)]; + + NSURL* openURL = [urlComponents URL]; + [self.extensionContext openURL:openURL completionHandler:nil]; } -+ (NSDictionary*)commandDict { - NSString* command = - base::SysUTF8ToNSString(app_group::kChromeAppGroupFocusOmniboxCommand); ++ (NSDictionary*)dictForCommand:(NSString*)command + parameter:(NSString*)parameter { NSString* timePrefKey = base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandTimePreference); NSString* appPrefKey = base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandAppPreference); NSString* commandPrefKey = base::SysUTF8ToNSString( app_group::kChromeAppGroupCommandCommandPreference); + + if (parameter) { + NSString* paramPrefKey = base::SysUTF8ToNSString( + app_group::kChromeAppGroupCommandParameterPreference); + return @{ + timePrefKey : [NSDate date], + appPrefKey : @"TodayExtension", + commandPrefKey : command, + paramPrefKey : parameter, + }; + } return @{ timePrefKey : [NSDate date], appPrefKey : @"TodayExtension",
diff --git a/media/audio/audio_output_delegate.h b/media/audio/audio_output_delegate.h index 0d9c540..3c12177 100644 --- a/media/audio/audio_output_delegate.h +++ b/media/audio/audio_output_delegate.h
@@ -32,9 +32,10 @@ // Called when construction is finished and the stream is ready for // playout. - virtual void OnStreamCreated(int stream_id, - base::SharedMemory* shared_memory, - base::CancelableSyncSocket* socket) = 0; + virtual void OnStreamCreated( + int stream_id, + base::SharedMemory* shared_memory, + std::unique_ptr<base::CancelableSyncSocket> socket) = 0; // Called if stream encounters an error and has become unusable. virtual void OnStreamError(int stream_id) = 0;
diff --git a/media/mojo/services/mojo_audio_output_stream.cc b/media/mojo/services/mojo_audio_output_stream.cc index 1be3171..cd656b82 100644 --- a/media/mojo/services/mojo_audio_output_stream.cc +++ b/media/mojo/services/mojo_audio_output_stream.cc
@@ -58,7 +58,7 @@ void MojoAudioOutputStream::OnStreamCreated( int stream_id, base::SharedMemory* shared_memory, - base::CancelableSyncSocket* foreign_socket) { + std::unique_ptr<base::CancelableSyncSocket> foreign_socket) { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(stream_created_callback_); DCHECK(shared_memory); @@ -71,7 +71,7 @@ mojo::ScopedSharedBufferHandle buffer_handle = mojo::WrapSharedMemoryHandle( foreign_memory_handle, shared_memory->requested_size(), false); mojo::ScopedHandle socket_handle = - mojo::WrapPlatformFile(foreign_socket->handle()); + mojo::WrapPlatformFile(foreign_socket->Release()); DCHECK(buffer_handle.is_valid()); DCHECK(socket_handle.is_valid());
diff --git a/media/mojo/services/mojo_audio_output_stream.h b/media/mojo/services/mojo_audio_output_stream.h index 533424e..ca5e5e5 100644 --- a/media/mojo/services/mojo_audio_output_stream.h +++ b/media/mojo/services/mojo_audio_output_stream.h
@@ -47,9 +47,10 @@ void SetVolume(double volume) override; // AudioOutputDelegate::EventHandler implementation. - void OnStreamCreated(int stream_id, - base::SharedMemory* shared_memory, - base::CancelableSyncSocket* foreign_socket) override; + void OnStreamCreated( + int stream_id, + base::SharedMemory* shared_memory, + std::unique_ptr<base::CancelableSyncSocket> foreign_socket) override; void OnStreamError(int stream_id) override; // Closes connection to client and notifies owner.
diff --git a/media/mojo/services/mojo_audio_output_stream_unittest.cc b/media/mojo/services/mojo_audio_output_stream_unittest.cc index c2b02a6..ce55ce88 100644 --- a/media/mojo/services/mojo_audio_output_stream_unittest.cc +++ b/media/mojo/services/mojo_audio_output_stream_unittest.cc
@@ -35,6 +35,26 @@ using AudioOutputStream = mojom::AudioOutputStream; using AudioOutputStreamPtr = mojo::InterfacePtr<AudioOutputStream>; +class TestCancelableSyncSocket : public base::CancelableSyncSocket { + public: + TestCancelableSyncSocket() {} + + void ExpectOwnershipTransfer() { expect_ownership_transfer_ = true; } + + ~TestCancelableSyncSocket() override { + // When the handle is sent over mojo, mojo takes ownership over it and + // closes it. We have to make sure we do not also retain the handle in the + // sync socket, as the sync socket closes the handle on destruction. + if (expect_ownership_transfer_) + EXPECT_EQ(handle(), kInvalidHandle); + } + + private: + bool expect_ownership_transfer_ = false; + + DISALLOW_COPY_AND_ASSIGN(TestCancelableSyncSocket); +}; + class MockDelegate : NON_EXPORTED_BASE(public AudioOutputDelegate) { public: MockDelegate() {} @@ -111,7 +131,8 @@ class MojoAudioOutputStreamTest : public Test { public: - MojoAudioOutputStreamTest() {} + MojoAudioOutputStreamTest() + : foreign_socket_(base::MakeUnique<TestCancelableSyncSocket>()) {} AudioOutputStreamPtr CreateAudioOutput() { AudioOutputStreamPtr p; @@ -132,14 +153,15 @@ mock_delegate_factory_.PrepareDelegateForCreation( base::WrapUnique(delegate_)); EXPECT_TRUE( - base::CancelableSyncSocket::CreatePair(&local_, &foreign_socket_)); + base::CancelableSyncSocket::CreatePair(&local_, foreign_socket_.get())); EXPECT_TRUE(mem_.CreateAnonymous(kShmemSize)); EXPECT_CALL(mock_delegate_factory_, MockCreateDelegate(NotNull())) .WillOnce(SaveArg<0>(&delegate_event_handler_)); } base::MessageLoop loop_; - base::CancelableSyncSocket local_, foreign_socket_; + base::CancelableSyncSocket local_; + std::unique_ptr<TestCancelableSyncSocket> foreign_socket_; base::SharedMemory mem_; StrictMock<MockDelegate>* delegate_ = nullptr; AudioOutputDelegate::EventHandler* delegate_event_handler_ = nullptr; @@ -178,7 +200,9 @@ base::RunLoop().RunUntilIdle(); ASSERT_NE(nullptr, delegate_event_handler_); - delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); + foreign_socket_->ExpectOwnershipTransfer(); + delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, + std::move(foreign_socket_)); audio_output_ptr->Play(); impl_.reset(); base::RunLoop().RunUntilIdle(); @@ -191,7 +215,9 @@ EXPECT_CALL(client_, GotNotification()); ASSERT_NE(nullptr, delegate_event_handler_); - delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); + foreign_socket_->ExpectOwnershipTransfer(); + delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, + std::move(foreign_socket_)); base::RunLoop().RunUntilIdle(); } @@ -231,7 +257,9 @@ base::RunLoop().RunUntilIdle(); ASSERT_NE(nullptr, delegate_event_handler_); - delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); + foreign_socket_->ExpectOwnershipTransfer(); + delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, + std::move(foreign_socket_)); delegate_event_handler_->OnStreamError(kStreamId); base::RunLoop().RunUntilIdle();
diff --git a/media/renderers/video_renderer_impl_unittest.cc b/media/renderers/video_renderer_impl_unittest.cc index 18743170..b57cc19 100644 --- a/media/renderers/video_renderer_impl_unittest.cc +++ b/media/renderers/video_renderer_impl_unittest.cc
@@ -560,7 +560,13 @@ InitializeRenderer(&new_stream, false, true); } -TEST_F(VideoRendererImplTest, DestroyWhileInitializing) { +// crbug.com/697171. +#if defined(MEMORY_SANITIZER) +#define MAYBE_DestroyWhileInitializing DISABLED_DestroyWhileInitializing +#else +#define MAYBE_DestroyWhileInitializing DestroyWhileInitializing +#endif +TEST_F(VideoRendererImplTest, MAYBE_DestroyWhileInitializing) { CallInitialize(&demuxer_stream_, NewExpectedStatusCB(PIPELINE_ERROR_ABORT), false, PIPELINE_OK); Destroy();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Document-createEvent-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Document-createEvent-expected.txt index ce12dec..6771837 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Document-createEvent-expected.txt +++ b/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Document-createEvent-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 331 tests; 304 PASS, 27 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 331 tests; 305 PASS, 26 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS AnimationEvent should be an alias for AnimationEvent. PASS createEvent('AnimationEvent') should be initialized correctly. PASS animationevent should be an alias for AnimationEvent. @@ -292,9 +292,7 @@ PASS Should throw NOT_SUPPORTED_ERR for pluralized non-legacy event interface "PresentationConnectionAvailableEvents" PASS Should throw NOT_SUPPORTED_ERR for non-legacy event interface "PresentationConnectionCloseEvent" PASS Should throw NOT_SUPPORTED_ERR for pluralized non-legacy event interface "PresentationConnectionCloseEvents" -FAIL Should throw NOT_SUPPORTED_ERR for non-legacy event interface "ProgressEvent" assert_throws: function "function () { - var evt = document.createEvent(eventInterface); - }" did not throw +PASS Should throw NOT_SUPPORTED_ERR for non-legacy event interface "ProgressEvent" PASS Should throw NOT_SUPPORTED_ERR for pluralized non-legacy event interface "ProgressEvents" PASS Should throw NOT_SUPPORTED_ERR for non-legacy event interface "PromiseRejectionEvent" PASS Should throw NOT_SUPPORTED_ERR for pluralized non-legacy event interface "PromiseRejectionEvents"
diff --git a/third_party/WebKit/LayoutTests/fast/events/event-creation-expected.txt b/third_party/WebKit/LayoutTests/fast/events/event-creation-expected.txt index fe9ab579..f4789d0f 100644 --- a/third_party/WebKit/LayoutTests/fast/events/event-creation-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/events/event-creation-expected.txt
@@ -72,9 +72,6 @@ PASS document.createEvent('PopStateEvent') instanceof window.PopStateEvent is true PASS document.createEvent('PopStateEvent') instanceof window.Event is true PASS document.createEvent('PopStateEvent').constructor === window.PopStateEvent is true -PASS document.createEvent('ProgressEvent') instanceof window.ProgressEvent is true -PASS document.createEvent('ProgressEvent') instanceof window.Event is true -PASS document.createEvent('ProgressEvent').constructor === window.ProgressEvent is true PASS document.createEvent('TextEvent') instanceof window.TextEvent is true PASS document.createEvent('TextEvent') instanceof window.UIEvent is true PASS document.createEvent('TextEvent') instanceof window.Event is true
diff --git a/third_party/WebKit/LayoutTests/fast/events/event-creation.html b/third_party/WebKit/LayoutTests/fast/events/event-creation.html index 1a2c028..e363cdf 100644 --- a/third_party/WebKit/LayoutTests/fast/events/event-creation.html +++ b/third_party/WebKit/LayoutTests/fast/events/event-creation.html
@@ -108,11 +108,6 @@ shouldBeTrue("document.createEvent('PopStateEvent') instanceof window.Event"); shouldBeTrue("document.createEvent('PopStateEvent').constructor === window.PopStateEvent"); - // ProgressEvent - shouldBeTrue("document.createEvent('ProgressEvent') instanceof window.ProgressEvent"); - shouldBeTrue("document.createEvent('ProgressEvent') instanceof window.Event"); - shouldBeTrue("document.createEvent('ProgressEvent').constructor === window.ProgressEvent"); - // TextEvent shouldBeTrue("document.createEvent('TextEvent') instanceof window.TextEvent"); shouldBeTrue("document.createEvent('TextEvent') instanceof window.UIEvent");
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/text-match-document-change-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/text-match-document-change-expected.png index 400bcf9..744ffd4b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/text-match-document-change-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/text-match-document-change-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/disable-spinvalidation/paint/invalidation/text-match-document-change-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/disable-spinvalidation/paint/invalidation/text-match-document-change-expected.png index 400bcf9..792b6d9d 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/disable-spinvalidation/paint/invalidation/text-match-document-change-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/disable-spinvalidation/paint/invalidation/text-match-document-change-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/text-match-document-change-expected.png b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/text-match-document-change-expected.png index 3cab44d..744ffd4b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/text-match-document-change-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/text-match-document-change-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/text-match-document-change-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/text-match-document-change-expected.png index 3cab44d..744ffd4b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/text-match-document-change-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/text-match-document-change-expected.png Binary files differ
diff --git a/third_party/WebKit/Source/build/scripts/make_event_factory.py b/third_party/WebKit/Source/build/scripts/make_event_factory.py index bea63b68..582a6c1e0a 100755 --- a/third_party/WebKit/Source/build/scripts/make_event_factory.py +++ b/third_party/WebKit/Source/build/scripts/make_event_factory.py
@@ -86,7 +86,6 @@ or name == 'MutationEvents' or name == 'PageTransitionEvent' or name == 'PopStateEvent' - or name == 'ProgressEvent' or name == 'StorageEvent' or name == 'SVGEvents' or name == 'TextEvent'
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp index 43fb66f..fc3101d 100644 --- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp +++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
@@ -508,6 +508,8 @@ node_iterator != end; ++node_iterator) { // inner loop; process each marker in this node const Node& node = *node_iterator->key; + if (!node.isConnected()) + continue; MarkerLists* markers = node_iterator->value.Get(); for (size_t marker_list_index = 0; marker_list_index < DocumentMarker::kMarkerTypeIndexesCount;
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h index 87f225e..515ef265 100644 --- a/third_party/WebKit/Source/core/frame/UseCounter.h +++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -895,7 +895,6 @@ kDocumentCreateEventMutationEvent = 1173, kDocumentCreateEventPageTransitionEvent = 1174, kDocumentCreateEventPopStateEvent = 1176, - kDocumentCreateEventProgressEvent = 1177, kDocumentCreateEventTextEvent = 1182, kDocumentCreateEventTransitionEvent = 1183, kDocumentCreateEventWheelEvent = 1184,
diff --git a/third_party/WebKit/Source/platform/graphics/CanvasSurfaceLayerBridge.cpp b/third_party/WebKit/Source/platform/graphics/CanvasSurfaceLayerBridge.cpp index 8630a777..02c63f86 100644 --- a/third_party/WebKit/Source/platform/graphics/CanvasSurfaceLayerBridge.cpp +++ b/third_party/WebKit/Source/platform/graphics/CanvasSurfaceLayerBridge.cpp
@@ -67,15 +67,15 @@ new OffscreenCanvasSurfaceReferenceFactory(weak_factory_.GetWeakPtr()); DCHECK(!service_.is_bound()); - mojom::blink::OffscreenCanvasSurfaceFactoryPtr service_factory; + mojom::blink::OffscreenCanvasProviderPtr provider; Platform::Current()->GetInterfaceProvider()->GetInterface( - mojo::MakeRequest(&service_factory)); + mojo::MakeRequest(&provider)); // TODO(xlai): Ensure OffscreenCanvas commit() is still functional when a // frame-less HTML canvas's document is reparenting under another frame. // See crbug.com/683172. - service_factory->CreateOffscreenCanvasSurface( - parent_frame_sink_id_, frame_sink_id_, - binding_.CreateInterfacePtrAndBind(), mojo::MakeRequest(&service_)); + provider->CreateOffscreenCanvasSurface(parent_frame_sink_id_, frame_sink_id_, + binding_.CreateInterfacePtrAndBind(), + mojo::MakeRequest(&service_)); } CanvasSurfaceLayerBridge::~CanvasSurfaceLayerBridge() {
diff --git a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp index 29d8a5e7..9e849684 100644 --- a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp +++ b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp
@@ -48,7 +48,7 @@ // mojo channel for this special case. current_local_surface_id_ = local_surface_id_allocator_.GenerateId(); DCHECK(!sink_.is_bound()); - mojom::blink::OffscreenCanvasCompositorFrameSinkProviderPtr provider; + mojom::blink::OffscreenCanvasProviderPtr provider; Platform::Current()->GetInterfaceProvider()->GetInterface( mojo::MakeRequest(&provider)); provider->CreateCompositorFrameSink(frame_sink_id_,
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferSoftwareRenderingTest.cpp b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferSoftwareRenderingTest.cpp index 34ced16..edcd8be5 100644 --- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferSoftwareRenderingTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferSoftwareRenderingTest.cpp
@@ -54,7 +54,8 @@ new WebGraphicsContext3DProviderSoftwareRenderingForTests( std::move(gl))); drawing_buffer_ = DrawingBufferForTests::Create( - std::move(provider), nullptr, initial_size, DrawingBuffer::kPreserve); + std::move(provider), nullptr, initial_size, DrawingBuffer::kPreserve, + kDisableMultisampling); CHECK(drawing_buffer_); }
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTest.cpp b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTest.cpp index 8d8becf..692dafc7 100644 --- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTest.cpp
@@ -66,7 +66,9 @@ class DrawingBufferTest : public Test { protected: - void SetUp() override { + void SetUp() override { Init(kDisableMultisampling); } + + void Init(UseMultisampling use_multisampling) { IntSize initial_size(kInitialWidth, kInitialHeight); std::unique_ptr<GLES2InterfaceForTests> gl = WTF::WrapUnique(new GLES2InterfaceForTests); @@ -76,7 +78,8 @@ WTF::WrapUnique( new WebGraphicsContext3DProviderForTests(std::move(gl))); drawing_buffer_ = DrawingBufferForTests::Create( - std::move(provider), gl_, initial_size, DrawingBuffer::kPreserve); + std::move(provider), gl_, initial_size, DrawingBuffer::kPreserve, + use_multisampling); CHECK(drawing_buffer_); } @@ -126,6 +129,27 @@ RefPtr<DrawingBufferForTests> drawing_buffer_; }; +class DrawingBufferTestMultisample : public DrawingBufferTest { + protected: + void SetUp() override { Init(kEnableMultisampling); } +}; + +TEST_F(DrawingBufferTestMultisample, verifyMultisampleResolve) { + // Initial state: already marked changed, multisampled + EXPECT_FALSE(drawing_buffer_->MarkContentsChanged()); + EXPECT_TRUE(drawing_buffer_->ExplicitResolveOfMultisampleData()); + + // Resolve the multisample buffer + drawing_buffer_->ResolveAndBindForReadAndDraw(); + + // After resolve, acknowledge new content + EXPECT_TRUE(drawing_buffer_->MarkContentsChanged()); + // No new content + EXPECT_FALSE(drawing_buffer_->MarkContentsChanged()); + + drawing_buffer_->BeginDestruction(); +} + TEST_F(DrawingBufferTest, verifyResizingProperlyAffectsMailboxes) { VerifyStateWasRestored(); cc::TextureMailbox texture_mailbox; @@ -135,7 +159,7 @@ IntSize alternate_size(kInitialWidth, kAlternateHeight); // Produce one mailbox at size 100x100. - drawing_buffer_->MarkContentsChanged(); + EXPECT_FALSE(drawing_buffer_->MarkContentsChanged()); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox(&texture_mailbox, &release_callback)); VerifyStateWasRestored(); @@ -148,7 +172,7 @@ VerifyStateWasRestored(); // Produce a mailbox at this size. - drawing_buffer_->MarkContentsChanged(); + EXPECT_TRUE(drawing_buffer_->MarkContentsChanged()); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox(&texture_mailbox, &release_callback)); EXPECT_EQ(alternate_size, gl_->MostRecentlyProducedSize()); @@ -162,7 +186,7 @@ VerifyStateWasRestored(); // Prepare another mailbox and verify that it's the correct size. - drawing_buffer_->MarkContentsChanged(); + EXPECT_TRUE(drawing_buffer_->MarkContentsChanged()); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox(&texture_mailbox, &release_callback)); EXPECT_EQ(initial_size, gl_->MostRecentlyProducedSize()); @@ -170,7 +194,7 @@ // Prepare one final mailbox and verify that it's the correct size. release_callback->Run(gpu::SyncToken(), false /* lostResource */); - drawing_buffer_->MarkContentsChanged(); + EXPECT_TRUE(drawing_buffer_->MarkContentsChanged()); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox(&texture_mailbox, &release_callback)); VerifyStateWasRestored(); @@ -193,23 +217,23 @@ IntSize initial_size(kInitialWidth, kInitialHeight); // Produce mailboxes. - drawing_buffer_->MarkContentsChanged(); + EXPECT_FALSE(drawing_buffer_->MarkContentsChanged()); drawing_buffer_->ClearFramebuffers(GL_STENCIL_BUFFER_BIT); VerifyStateWasRestored(); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox(&texture_mailbox1, &release_callback1)); - drawing_buffer_->MarkContentsChanged(); + EXPECT_TRUE(drawing_buffer_->MarkContentsChanged()); drawing_buffer_->ClearFramebuffers(GL_DEPTH_BUFFER_BIT); VerifyStateWasRestored(); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox(&texture_mailbox2, &release_callback2)); - drawing_buffer_->MarkContentsChanged(); + EXPECT_TRUE(drawing_buffer_->MarkContentsChanged()); drawing_buffer_->ClearFramebuffers(GL_COLOR_BUFFER_BIT); VerifyStateWasRestored(); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox(&texture_mailbox3, &release_callback3)); - drawing_buffer_->MarkContentsChanged(); + EXPECT_TRUE(drawing_buffer_->MarkContentsChanged()); release_callback1->Run(gpu::SyncToken(), false /* lostResource */); drawing_buffer_->BeginDestruction(); @@ -219,11 +243,11 @@ drawing_buffer_.Clear(); ASSERT_EQ(live, true); - raw_pointer->MarkContentsChanged(); + EXPECT_FALSE(raw_pointer->MarkContentsChanged()); release_callback2->Run(gpu::SyncToken(), false /* lostResource */); ASSERT_EQ(live, true); - raw_pointer->MarkContentsChanged(); + EXPECT_FALSE(raw_pointer->MarkContentsChanged()); release_callback3->Run(gpu::SyncToken(), false /* lostResource */); ASSERT_EQ(live, false); } @@ -239,27 +263,27 @@ cc::TextureMailbox texture_mailbox3; std::unique_ptr<cc::SingleReleaseCallback> release_callback3; - drawing_buffer_->MarkContentsChanged(); + EXPECT_FALSE(drawing_buffer_->MarkContentsChanged()); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox(&texture_mailbox1, &release_callback1)); VerifyStateWasRestored(); - drawing_buffer_->MarkContentsChanged(); + EXPECT_TRUE(drawing_buffer_->MarkContentsChanged()); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox(&texture_mailbox2, &release_callback2)); VerifyStateWasRestored(); - drawing_buffer_->MarkContentsChanged(); + EXPECT_TRUE(drawing_buffer_->MarkContentsChanged()); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox(&texture_mailbox3, &release_callback3)); VerifyStateWasRestored(); - drawing_buffer_->MarkContentsChanged(); + EXPECT_TRUE(drawing_buffer_->MarkContentsChanged()); release_callback1->Run(gpu::SyncToken(), true /* lostResource */); EXPECT_EQ(live, true); drawing_buffer_->BeginDestruction(); EXPECT_EQ(live, true); - drawing_buffer_->MarkContentsChanged(); + EXPECT_FALSE(drawing_buffer_->MarkContentsChanged()); release_callback2->Run(gpu::SyncToken(), false /* lostResource */); EXPECT_EQ(live, true); @@ -267,7 +291,7 @@ drawing_buffer_.Clear(); EXPECT_EQ(live, true); - raw_ptr->MarkContentsChanged(); + EXPECT_FALSE(raw_ptr->MarkContentsChanged()); release_callback3->Run(gpu::SyncToken(), true /* lostResource */); EXPECT_EQ(live, false); } @@ -281,29 +305,29 @@ std::unique_ptr<cc::SingleReleaseCallback> release_callback3; // Produce mailboxes. - drawing_buffer_->MarkContentsChanged(); + EXPECT_FALSE(drawing_buffer_->MarkContentsChanged()); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox(&texture_mailbox1, &release_callback1)); - drawing_buffer_->MarkContentsChanged(); + EXPECT_TRUE(drawing_buffer_->MarkContentsChanged()); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox(&texture_mailbox2, &release_callback2)); - drawing_buffer_->MarkContentsChanged(); + EXPECT_TRUE(drawing_buffer_->MarkContentsChanged()); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox(&texture_mailbox3, &release_callback3)); // Release mailboxes by specific order; 1, 3, 2. - drawing_buffer_->MarkContentsChanged(); + EXPECT_TRUE(drawing_buffer_->MarkContentsChanged()); release_callback1->Run(gpu::SyncToken(), false /* lostResource */); - drawing_buffer_->MarkContentsChanged(); + EXPECT_FALSE(drawing_buffer_->MarkContentsChanged()); release_callback3->Run(gpu::SyncToken(), false /* lostResource */); - drawing_buffer_->MarkContentsChanged(); + EXPECT_FALSE(drawing_buffer_->MarkContentsChanged()); release_callback2->Run(gpu::SyncToken(), false /* lostResource */); // The first recycled mailbox must be 2. 1 and 3 were deleted by FIFO order // because DrawingBuffer never keeps more than one mailbox. cc::TextureMailbox recycled_texture_mailbox1; std::unique_ptr<cc::SingleReleaseCallback> recycled_release_callback1; - drawing_buffer_->MarkContentsChanged(); + EXPECT_FALSE(drawing_buffer_->MarkContentsChanged()); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox( &recycled_texture_mailbox1, &recycled_release_callback1)); EXPECT_EQ(texture_mailbox2.mailbox(), recycled_texture_mailbox1.mailbox()); @@ -311,7 +335,7 @@ // The second recycled mailbox must be a new mailbox. cc::TextureMailbox recycled_texture_mailbox2; std::unique_ptr<cc::SingleReleaseCallback> recycled_release_callback2; - drawing_buffer_->MarkContentsChanged(); + EXPECT_TRUE(drawing_buffer_->MarkContentsChanged()); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox( &recycled_texture_mailbox2, &recycled_release_callback2)); EXPECT_NE(texture_mailbox1.mailbox(), recycled_texture_mailbox2.mailbox()); @@ -328,7 +352,7 @@ std::unique_ptr<cc::SingleReleaseCallback> release_callback; // Produce mailboxes. - drawing_buffer_->MarkContentsChanged(); + EXPECT_FALSE(drawing_buffer_->MarkContentsChanged()); EXPECT_EQ(gpu::SyncToken(), gl_->MostRecentlyWaitedSyncToken()); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox(&texture_mailbox, &release_callback)); @@ -342,7 +366,7 @@ // m_drawingBuffer will wait for the sync point when recycling. EXPECT_EQ(gpu::SyncToken(), gl_->MostRecentlyWaitedSyncToken()); - drawing_buffer_->MarkContentsChanged(); + EXPECT_TRUE(drawing_buffer_->MarkContentsChanged()); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox(&texture_mailbox, &release_callback)); // m_drawingBuffer waits for the sync point when recycling in @@ -375,7 +399,8 @@ image_id0_ = gl_->NextImageIdToBeCreated(); EXPECT_CALL(*gl_, BindTexImage2DMock(image_id0_)).Times(1); drawing_buffer_ = DrawingBufferForTests::Create( - std::move(provider), gl_, initial_size, DrawingBuffer::kPreserve); + std::move(provider), gl_, initial_size, DrawingBuffer::kPreserve, + kDisableMultisampling); CHECK(drawing_buffer_); testing::Mock::VerifyAndClearExpectations(gl_); } @@ -399,7 +424,7 @@ GLuint image_id1 = gl_->NextImageIdToBeCreated(); EXPECT_CALL(*gl_, BindTexImage2DMock(image_id1)).Times(1); // Produce one mailbox at size 100x100. - drawing_buffer_->MarkContentsChanged(); + EXPECT_FALSE(drawing_buffer_->MarkContentsChanged()); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox(&texture_mailbox, &release_callback)); EXPECT_EQ(initial_size, gl_->MostRecentlyProducedSize()); @@ -423,7 +448,7 @@ GLuint image_id3 = gl_->NextImageIdToBeCreated(); EXPECT_CALL(*gl_, BindTexImage2DMock(image_id3)).Times(1); // Produce a mailbox at this size. - drawing_buffer_->MarkContentsChanged(); + EXPECT_TRUE(drawing_buffer_->MarkContentsChanged()); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox(&texture_mailbox, &release_callback)); EXPECT_EQ(alternate_size, gl_->MostRecentlyProducedSize()); @@ -446,7 +471,7 @@ GLuint image_id5 = gl_->NextImageIdToBeCreated(); EXPECT_CALL(*gl_, BindTexImage2DMock(image_id5)).Times(1); // Prepare another mailbox and verify that it's the correct size. - drawing_buffer_->MarkContentsChanged(); + EXPECT_TRUE(drawing_buffer_->MarkContentsChanged()); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox(&texture_mailbox, &release_callback)); EXPECT_EQ(initial_size, gl_->MostRecentlyProducedSize()); @@ -455,7 +480,7 @@ // Prepare one final mailbox and verify that it's the correct size. release_callback->Run(gpu::SyncToken(), false /* lostResource */); - drawing_buffer_->MarkContentsChanged(); + EXPECT_TRUE(drawing_buffer_->MarkContentsChanged()); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox(&texture_mailbox, &release_callback)); EXPECT_EQ(initial_size, gl_->MostRecentlyProducedSize()); @@ -482,7 +507,7 @@ // as expected. EXPECT_CALL(*gl_, BindTexImage2DMock(_)).Times(1); IntSize initial_size(kInitialWidth, kInitialHeight); - drawing_buffer_->MarkContentsChanged(); + EXPECT_FALSE(drawing_buffer_->MarkContentsChanged()); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox(&texture_mailbox1, &release_callback1)); EXPECT_TRUE(texture_mailbox1.is_overlay_candidate()); @@ -492,7 +517,7 @@ // Force image CHROMIUM creation failure. Request another mailbox. It should // still be provided, but this time with allowOverlay = false. gl_->SetCreateImageChromiumFail(true); - drawing_buffer_->MarkContentsChanged(); + EXPECT_TRUE(drawing_buffer_->MarkContentsChanged()); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox(&texture_mailbox2, &release_callback2)); EXPECT_FALSE(texture_mailbox2.is_overlay_candidate()); @@ -502,7 +527,7 @@ // correctly created with allowOverlay = true. EXPECT_CALL(*gl_, BindTexImage2DMock(_)).Times(1); gl_->SetCreateImageChromiumFail(false); - drawing_buffer_->MarkContentsChanged(); + EXPECT_TRUE(drawing_buffer_->MarkContentsChanged()); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox(&texture_mailbox3, &release_callback3)); EXPECT_TRUE(texture_mailbox3.is_overlay_candidate()); @@ -673,7 +698,7 @@ std::unique_ptr<cc::SingleReleaseCallback> release_callback; // Produce mailboxes. - drawing_buffer_->MarkContentsChanged(); + EXPECT_FALSE(drawing_buffer_->MarkContentsChanged()); EXPECT_TRUE(drawing_buffer_->PrepareTextureMailbox(&texture_mailbox, &release_callback));
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTestHelpers.h b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTestHelpers.h index fa44cfc..7cc062f 100644 --- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTestHelpers.h +++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTestHelpers.h
@@ -18,21 +18,27 @@ kAlternateHeight = 50, }; +enum UseMultisampling { + kDisableMultisampling, + kEnableMultisampling, +}; + class DrawingBufferForTests : public DrawingBuffer { public: static PassRefPtr<DrawingBufferForTests> Create( std::unique_ptr<WebGraphicsContext3DProvider> context_provider, DrawingBuffer::Client* client, const IntSize& size, - PreserveDrawingBuffer preserve) { + PreserveDrawingBuffer preserve, + UseMultisampling use_multisampling) { std::unique_ptr<Extensions3DUtil> extensions_util = Extensions3DUtil::Create(context_provider->ContextGL()); RefPtr<DrawingBufferForTests> drawing_buffer = AdoptRef(new DrawingBufferForTests(std::move(context_provider), std::move(extensions_util), client, preserve)); - bool multisample_extension_supported = false; - if (!drawing_buffer->Initialize(size, multisample_extension_supported)) { + if (!drawing_buffer->Initialize( + size, use_multisampling != kDisableMultisampling)) { drawing_buffer->BeginDestruction(); return nullptr; }
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py index 1369b74..1a830a3 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py
@@ -793,7 +793,8 @@ log_callback('installing apk if necessary') self._device.Install(driver_host_path) except (device_errors.CommandFailedError, - device_errors.CommandTimeoutError) as exc: + device_errors.CommandTimeoutError, + device_errors.DeviceUnreachableError) as exc: self._abort('Failed to install %s onto device: %s' % (driver_host_path, str(exc))) def _push_fonts(self, log_callback):
diff --git a/third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom b/third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom index 9626b9d..d17270b 100644 --- a/third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom +++ b/third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom
@@ -4,7 +4,6 @@ module blink.mojom; -import "cc/ipc/compositor_frame.mojom"; import "cc/ipc/frame_sink_id.mojom"; import "cc/ipc/frame_sink_manager.mojom"; import "cc/ipc/mojo_compositor_frame_sink.mojom"; @@ -16,17 +15,20 @@ Satisfy(cc.mojom.SurfaceSequence sequence); }; -interface OffscreenCanvasSurfaceFactory { +// Creates OffscreenCanvasSurface and MojoCompositorFrameSink instances for use +// with offscreen canvas. +interface OffscreenCanvasProvider { + // TODO(kylechar): Observer interface shouldn't be FrameSinkManagerClient. + // Create an OffscreenCanvasSurface for |frame_sink_id|. |client| will observe + // any changes to the SurfaceId associated with |frame_sink_id|. CreateOffscreenCanvasSurface(cc.mojom.FrameSinkId parent_frame_sink_id, cc.mojom.FrameSinkId frame_sink_id, cc.mojom.FrameSinkManagerClient client, - OffscreenCanvasSurface& service); -}; + OffscreenCanvasSurface& surface); -interface OffscreenCanvasCompositorFrameSinkProvider { - // TODO(fsamuel, xlai): Replace this with FrameSinkManager + // Create an MojoCompositorFrameSink for |frame_sink_id|. This must happen + // after creating an OffsreenCanvasSurface for |frame_sink_id|. CreateCompositorFrameSink(cc.mojom.FrameSinkId frame_sink_id, cc.mojom.MojoCompositorFrameSinkClient client, cc.mojom.MojoCompositorFrameSink& sink); -}; - +}; \ No newline at end of file
diff --git a/tools/cygprofile/profile_android_startup.py b/tools/cygprofile/profile_android_startup.py index 96d1b4c..914f7d19 100755 --- a/tools/cygprofile/profile_android_startup.py +++ b/tools/cygprofile/profile_android_startup.py
@@ -230,7 +230,8 @@ self._device.PushChangedFiles([(self._cygprofile_tests, device_path)]) try: self._device.RunShellCommand(device_path, check_return=True) - except device_errors.CommandFailedError: + except (device_errors.CommandFailedError, + device_errors.DeviceUnreachableError): # TODO(jbudorick): Let the exception propagate up once clients can # handle it. logging.exception('Failure while running cygprofile_unittests:')