Skip to content
Draft
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
14 changes: 14 additions & 0 deletions test-app/app/src/main/java/com/tns/NativeScriptRuntime.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.tns;

public final class NativeScriptRuntime {
private NativeScriptRuntime() {
}

public static boolean reloadApplication() {
return RuntimeHelper.reloadApplication();
}

public static boolean reloadApplication(String baseDir) {
return RuntimeHelper.reloadApplication();
}
}
53 changes: 52 additions & 1 deletion test-app/app/src/main/java/com/tns/RuntimeHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import android.content.SharedPreferences;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.preference.PreferenceManager;
import android.util.Log;

Expand All @@ -24,6 +26,9 @@ private RuntimeHelper() {
}

private static AndroidJsV8Inspector v8Inspector;
private static Context applicationContext;
private static BroadcastReceiver timezoneChangedReceiver;
private static boolean reloadScheduled;

// hasErrorIntent tells you if there was an event (with an uncaught
// exception) raised from ErrorReport
Expand Down Expand Up @@ -59,6 +64,9 @@ private static boolean hasErrorIntent(Context context) {
}

public static Runtime initRuntime(Context context) {
Context appContext = context.getApplicationContext();
applicationContext = appContext != null ? appContext : context;

if (Runtime.isInitialized()) {
return Runtime.getCurrentRuntime();
}
Expand Down Expand Up @@ -237,6 +245,40 @@ public static Runtime initRuntime(Context context) {
}
}

public static synchronized boolean reloadApplication() {
final Context context = applicationContext;
if (context == null || reloadScheduled) {
return false;
}

reloadScheduled = true;

new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
try {
Runtime.destroyMainRuntime();

Runtime runtime = initRuntime(context);
if (runtime == null) {
throw new IllegalStateException("NativeScript runtime reload failed to initialize a new runtime.");
}

runtime.run();
} catch (Throwable e) {
Log.e(logTag, "NativeScript runtime reload failed.", e);
throw new RuntimeException("NativeScript runtime reload failed.", e);
} finally {
synchronized (RuntimeHelper.class) {
reloadScheduled = false;
}
}
}
});

return true;
}

private static void waitForLiveSync(Context context) {
boolean needToWait = false;

Expand Down Expand Up @@ -295,7 +337,16 @@ public void onReceive(Context context, Intent intent) {
}
};

context.registerReceiver(timezoneReceiver, timezoneFilter);
if (timezoneChangedReceiver != null) {
try {
context.unregisterReceiver(timezoneChangedReceiver);
} catch (IllegalArgumentException e) {
// Already unregistered.
}
}

timezoneChangedReceiver = timezoneReceiver;
context.registerReceiver(timezoneChangedReceiver, timezoneFilter);
}

public static void initLiveSync(Application app) {
Expand Down
25 changes: 24 additions & 1 deletion test-app/runtime/src/main/cpp/com_tns_Runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ extern "C" JNIEXPORT void Java_com_tns_Runtime_TerminateWorkerCallback(JNIEnv* e
auto runtime = TryGetRuntime(runtimeId);
if (runtime == nullptr) {
// TODO: Pete: Log message informing the developer of the failure
return;
}

auto isolate = runtime->GetIsolate();
Expand All @@ -440,6 +441,28 @@ extern "C" JNIEXPORT void Java_com_tns_Runtime_TerminateWorkerCallback(JNIEnv* e
delete runtime;
}

extern "C" JNIEXPORT void Java_com_tns_Runtime_TerminateRuntimeCallback(JNIEnv* env, jobject obj, jint runtimeId) {
auto runtime = TryGetRuntime(runtimeId);
if (runtime == nullptr) {
// TODO: Pete: Log message informing the developer of the failure
return;
}

auto isolate = runtime->GetIsolate();

{
v8::Locker locker(isolate);
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handleScope(isolate);

runtime->DestroyRuntime();
}

isolate->Dispose();

delete runtime;
}

extern "C" JNIEXPORT void Java_com_tns_Runtime_ClearWorkerPersistent(JNIEnv* env, jobject obj, jint runtimeId, jint workerId) {
// Worker Thread runtime
auto runtime = TryGetRuntime(runtimeId);
Expand Down Expand Up @@ -487,4 +510,4 @@ extern "C" JNIEXPORT void Java_com_tns_Runtime_ResetDateTimeConfigurationCache(J

auto isolate = runtime->GetIsolate();
isolate->DateTimeConfigurationChangeNotification(Isolate::TimeZoneDetection::kRedetect);
}
}
36 changes: 36 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 @@ -118,6 +118,8 @@ public static void SetManualInstrumentationMode(String mode) {

private static native void TerminateWorkerCallback(int runtimeId);

private static native void TerminateRuntimeCallback(int runtimeId);

private static native void ClearWorkerPersistent(int runtimeId, int workerId);

private static native void CallWorkerObjectOnErrorHandleMain(int runtimeId, int workerId, String message, String stackTrace, String filename, int lineno, String threadName) throws NativeScriptException;
Expand Down Expand Up @@ -486,6 +488,40 @@ public static boolean isInitialized() {
return (runtime != null) ? runtime.isInitializedImpl() : false;
}

static void destroyMainRuntime() {
Runtime runtime = Runtime.getCurrentRuntime();
if (runtime == null) {
return;
}

if (runtime.workerId != 0) {
throw new NativeScriptException("Only the main NativeScript runtime can be destroyed with destroyMainRuntime().");
}

runtime.isTerminating = true;
runtime.terminateWorkers();
GcListener.unsubscribe(runtime);
runtimeCache.remove(runtime.runtimeId);
pendingWorkerMessages.clear();
currentRuntime.remove();

TerminateRuntimeCallback(runtime.runtimeId);
}

private void terminateWorkers() {
for (Handler workerHandler : new ArrayList<>(workerIdToHandler.values())) {
if (workerHandler == null) {
continue;
}

Message msg = Message.obtain();
msg.arg1 = MessageType.TerminateThread;
workerHandler.sendMessageAtFrontOfQueue(msg);
}

workerIdToHandler.clear();
}

public int getWorkerId() {
return workerId;
}
Expand Down
Loading