Skip to content

Invalidate V8 DateTime cache on timezone changes #1033

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions test-app/app/src/main/java/com/tns/RuntimeHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@
import java.io.File;

import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.preference.PreferenceManager;
import android.util.Log;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.TimeZone;

public final class RuntimeHelper {
private RuntimeHelper() {
Expand Down Expand Up @@ -233,12 +239,54 @@ public static Runtime initRuntime(Application app) {
}
e.printStackTrace();
}

if (appConfig.handleTimeZoneChanges()) {
// If the user sets this flag, we will register a broadcast receiver
// that will listen for the TIMEZONE_CHANGED event and update V8's cache
// so that subsequent calls to "new Date()" return the new timezone
registerTimezoneChangedListener(app, runtime);
}
}
return runtime;
} finally {
frame.close();
}
}

private static void registerTimezoneChangedListener(Context context, final Runtime runtime) {
IntentFilter timezoneFilter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED);

BroadcastReceiver timezoneReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action == null || !action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
return;
}

SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);

String oldTimezone = prefs.getString(PREF_TIMEZONE, null);
String newTimezone = TimeZone.getDefault().getID();
if (newTimezone == null) {
newTimezone = "";
}

if (oldTimezone == null) {
oldTimezone = "";
}

if (!oldTimezone.equals(newTimezone)) {
prefs.edit().putString(PREF_TIMEZONE, newTimezone).commit();
// Notify V8 for the timezone change
runtime.ResetDateTimeConfigurationCache();
}
}
};

context.registerReceiver(timezoneReceiver, timezoneFilter);
}

private static final String logTag = "MyApp";
private static final String PREF_TIMEZONE = "_android_runtime_pref_timezone_";
}
10 changes: 10 additions & 0 deletions test-app/runtime/src/main/cpp/com_tns_Runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -347,4 +347,14 @@ extern "C" JNIEXPORT void Java_com_tns_Runtime_CallWorkerObjectOnErrorHandleMain
} catch (NativeScriptException& e) {
e.ReThrowToJava();
}
}

extern "C" JNIEXPORT void Java_com_tns_Runtime_ResetDateTimeConfigurationCache(JNIEnv* _env, jobject obj, jint runtimeId) {
auto runtime = TryGetRuntime(runtimeId);
if (runtime == nullptr) {
return;
}

auto isolate = runtime->GetIsolate();
Date::DateTimeConfigurationChangeNotification(isolate);
}
10 changes: 9 additions & 1 deletion test-app/runtime/src/main/java/com/tns/AppConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ protected enum KnownKeys {
MemoryCheckInterval("memoryCheckInterval", 0),
FreeMemoryRatio("freeMemoryRatio", 0.0),
Profiling("profiling", ""),
MarkingMode("markingMode", com.tns.MarkingMode.full);
MarkingMode("markingMode", com.tns.MarkingMode.full),
HandleTimeZoneChanges("handleTimeZoneChanges", false);

private final String name;
private final Object defaultValue;
Expand Down Expand Up @@ -100,6 +101,9 @@ public AppConfig(File appDir) {
Log.v("JS", "Failed to parse marking mode. The default " + ((MarkingMode)KnownKeys.MarkingMode.getDefaultValue()).name() + " will be used.");
}
}
if (androidObject.has(KnownKeys.HandleTimeZoneChanges.getName())) {
values[KnownKeys.HandleTimeZoneChanges.ordinal()] = androidObject.getBoolean(KnownKeys.HandleTimeZoneChanges.getName());
}
}
}
} catch (Exception e) {
Expand Down Expand Up @@ -138,4 +142,8 @@ public String getProfilingMode() {
public MarkingMode getMarkingMode() {
return (MarkingMode)values[KnownKeys.MarkingMode.ordinal()];
}

public boolean handleTimeZoneChanges() {
return (boolean)values[KnownKeys.HandleTimeZoneChanges.ordinal()];
}
}
9 changes: 9 additions & 0 deletions test-app/runtime/src/main/java/com/tns/Runtime.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ public class Runtime {

private static native void CallWorkerObjectOnErrorHandleMain(int runtimeId, int workerId, String message, String stackTrace, String filename, int lineno, String threadName) throws NativeScriptException;

private static native void ResetDateTimeConfigurationCache(int runtimeId);

void passUncaughtExceptionToJs(Throwable ex, String stackTrace) {
passUncaughtExceptionToJsNative(getRuntimeId(), ex, stackTrace);
}
Expand Down Expand Up @@ -224,6 +226,13 @@ public Handler getHandler() {
return this.threadScheduler.getHandler();
}

public void ResetDateTimeConfigurationCache() {
Runtime runtime = getCurrentRuntime();
if (runtime != null) {
ResetDateTimeConfigurationCache(runtime.getRuntimeId());
}
}

private static class WorkerThreadHandler extends Handler {
@Override
public void handleMessage(Message msg) {
Expand Down