From 12a87b66742b4f65418bd17ee299675ebed01acb Mon Sep 17 00:00:00 2001 From: Krishna Monian Date: Wed, 15 Jun 2016 13:13:09 -0700 Subject: [PATCH] Fix lost callbacks due to time drift between server and emulator Reviewed By: yungsters Differential Revision: D3434921 fbshipit-source-id: ec82374a8ed322d99beadac78a415f952ceb3ec8 --- .../java/com/facebook/react/testing/BUCK | 17 +++++++++-------- .../react/testing/ReactIntegrationTestCase.java | 4 +++- .../com/facebook/react/CoreModulesPackage.java | 2 +- .../com/facebook/react/modules/core/Timing.java | 12 +++++++++++- .../test/java/com/facebook/react/modules/BUCK | 1 + .../react/modules/timing/TimingModuleTest.java | 3 ++- 6 files changed, 27 insertions(+), 12 deletions(-) diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/BUCK b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/BUCK index 590d0bf4b..98b21685a 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/BUCK +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/BUCK @@ -4,20 +4,21 @@ android_library( name = 'testing', srcs = glob(['**/*.java']), deps = [ - react_native_target('java/com/facebook/react:react'), - react_native_target('java/com/facebook/react/bridge:bridge'), - react_native_target('java/com/facebook/react/common:common'), - react_native_target('java/com/facebook/react/modules/core:core'), - react_native_target('java/com/facebook/react/modules/debug:debug'), - react_native_target('java/com/facebook/react/devsupport:devsupport'), - react_native_target('java/com/facebook/react/shell:shell'), - react_native_target('java/com/facebook/react/uimanager:uimanager'), react_native_dep('libraries/soloader/java/com/facebook/soloader:soloader'), react_native_dep('third-party/android/support/v4:lib-support-v4'), react_native_dep('third-party/java/infer-annotations:infer-annotations'), react_native_dep('third-party/java/jsr-305:jsr-305'), react_native_dep('third-party/java/junit:junit'), + react_native_dep('third-party/java/mockito:mockito'), react_native_dep('third-party/java/testing-support-lib:runner'), + react_native_target('java/com/facebook/react/bridge:bridge'), + react_native_target('java/com/facebook/react/common:common'), + react_native_target('java/com/facebook/react/devsupport:devsupport'), + react_native_target('java/com/facebook/react/modules/core:core'), + react_native_target('java/com/facebook/react/modules/debug:debug'), + react_native_target('java/com/facebook/react/shell:shell'), + react_native_target('java/com/facebook/react/uimanager:uimanager'), + react_native_target('java/com/facebook/react:react'), ], visibility = [ 'PUBLIC', diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java index 8f24a0c1d..8591cfeaa 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java @@ -30,10 +30,12 @@ import com.facebook.react.bridge.SoftAssertions; import com.facebook.react.bridge.UiThreadUtil; import com.facebook.react.common.ApplicationHolder; import com.facebook.react.common.futures.SimpleSettableFuture; +import com.facebook.react.devsupport.DevSupportManager; import com.facebook.react.modules.core.Timing; import com.facebook.soloader.SoLoader; +import static org.mockito.Mockito.*; /** * Use this class for writing integration tests of catalyst. This class will run all JNI call @@ -137,7 +139,7 @@ public abstract class ReactIntegrationTestCase extends AndroidTestCase { new Runnable() { @Override public void run() { - Timing timing = new Timing(getContext()); + Timing timing = new Timing(getContext(), mock(DevSupportManager.class)); simpleSettableFuture.set(timing); } }); diff --git a/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java b/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java index 8be15fb6d..389e48519 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java +++ b/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java @@ -80,7 +80,7 @@ import com.facebook.systrace.Systrace; new AndroidInfoModule(), new DeviceEventManagerModule(catalystApplicationContext, mHardwareBackBtnHandler), new ExceptionsManagerModule(mReactInstanceManager.getDevSupportManager()), - new Timing(catalystApplicationContext), + new Timing(catalystApplicationContext, mReactInstanceManager.getDevSupportManager()), new SourceCodeModule(mReactInstanceManager.getSourceUrl()), uiManagerModule, new JSCHeapCapture(catalystApplicationContext), diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java b/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java index 91a6ddc7c..01bf221bf 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java @@ -30,6 +30,7 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.WritableArray; import com.facebook.react.common.SystemClock; +import com.facebook.react.devsupport.DevSupportManager; import com.facebook.react.uimanager.ReactChoreographer; /** @@ -38,6 +39,8 @@ import com.facebook.react.uimanager.ReactChoreographer; public final class Timing extends ReactContextBaseJavaModule implements LifecycleEventListener, OnExecutorUnregisteredListener { + private final DevSupportManager mDevSupportManager; + private static class Timer { private final ExecutorToken mExecutorToken; @@ -112,8 +115,9 @@ public final class Timing extends ReactContextBaseJavaModule implements Lifecycl private @Nullable ReactChoreographer mReactChoreographer; private boolean mFrameCallbackPosted = false; - public Timing(ReactApplicationContext reactContext) { + public Timing(ReactApplicationContext reactContext, DevSupportManager devSupportManager) { super(reactContext); + mDevSupportManager = devSupportManager; // We store timers sorted by finish time. mTimers = new PriorityQueue( 11, // Default capacity: for some reason they don't expose a (Comparator) constructor @@ -213,6 +217,12 @@ public final class Timing extends ReactContextBaseJavaModule implements Lifecycl final int duration, final double jsSchedulingTime, final boolean repeat) { + // If the times on the server and device have drifted throw an exception to warn the developer + // that things might not work or results may not be accurate. This is required only for + // developer builds. + if (mDevSupportManager.getDevSupportEnabled() && Math.abs(jsSchedulingTime - System.currentTimeMillis()) > 1000) { + throw new RuntimeException("System and emulator/device times have drifted. Please correct this by running adb shell \"date `date +%m%d%H%M%Y.%S`\" on your dev machine"); + } // Adjust for the amount of time it took for native to receive the timer registration call long adjustedDuration = (long) Math.max( 0, diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/BUCK b/ReactAndroid/src/test/java/com/facebook/react/modules/BUCK index 19787b131..dd6620ac2 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/modules/BUCK +++ b/ReactAndroid/src/test/java/com/facebook/react/modules/BUCK @@ -6,6 +6,7 @@ robolectric3_test( name = 'modules', srcs = glob(['**/*.java']), deps = [ + react_native_dep('java/com/facebook/catalyst/js/react-native-github/ReactAndroid/src/main/java/com/facebook/react/devsupport:devsupport'), react_native_dep('libraries/fbcore/src/test/java/com/facebook/powermock:powermock'), react_native_dep('third-party/java/fest:fest'), react_native_dep('third-party/java/junit:junit'), diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java index e6185a8f0..7eebda7f1 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java @@ -16,6 +16,7 @@ import com.facebook.react.bridge.ExecutorToken; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.CatalystInstance; import com.facebook.react.bridge.JavaOnlyArray; +import com.facebook.react.devsupport.DevSupportManager; import com.facebook.react.uimanager.ReactChoreographer; import com.facebook.react.common.SystemClock; import com.facebook.react.modules.core.JSTimersExecution; @@ -92,7 +93,7 @@ public class TimingModuleTest { eq(ReactChoreographer.CallbackType.TIMERS_EVENTS), any(Choreographer.FrameCallback.class)); - mTiming = new Timing(reactContext); + mTiming = new Timing(reactContext, mock(DevSupportManager.class)); mJSTimersMock = mock(JSTimersExecution.class); mExecutorTokenMock = mock(ExecutorToken.class); when(reactContext.getJSModule(mExecutorTokenMock, JSTimersExecution.class)).thenReturn(mJSTimersMock);