Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.util.Log;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0

import java.io.IOException;

public final class RuntimeHelper {
Expand All @@ -28,7 +29,7 @@ private static boolean hasErrorIntent(Application app) {
try {
java.lang.Class ErrReport = java.lang.Class.forName("com.tns.ErrorReport");
java.lang.reflect.Field field = ErrReport.getDeclaredField("ERROR_FILE_NAME");
fileName = (String)field.get(null);
fileName = (String) field.get(null);
} catch (Exception e) {
return false;
}
Expand Down Expand Up @@ -97,7 +98,7 @@ public static Runtime initRuntime(Application app) {
logger.write("Extracting snapshot blob");
}

aE.extractAssets(app, "snapshots/" + Build.CPU_ABI, outputDir, extractPolicy);
aE.extractAssets(app, "snapshots/" + Build.CPU_ABI, outputDir, extractPolicy);
}

extractPolicy.setAssetsThumb(app);
Expand Down Expand Up @@ -131,17 +132,32 @@ public static Runtime initRuntime(Application app) {
runtime = Runtime.initializeRuntimeWithConfiguration(config);
if (isDebuggable) {
try {
v8Inspector = new AndroidJsV8Inspector(app, logger);
v8Inspector = new AndroidJsV8Inspector(app.getFilesDir().getAbsolutePath(), app.getPackageName());
v8Inspector.start();

// the following snippet is used as means to notify the VSCode extension
// debugger that the debugger agent has started
File debugBreakFile = new File("/data/local/tmp", app.getPackageName() + "-debugger-started");
File debuggerStartedFile = new File("/data/local/tmp", app.getPackageName() + "-debugger-started");
if (debuggerStartedFile.exists() && !debuggerStartedFile.isDirectory() && debuggerStartedFile.length() == 0) {
java.io.FileWriter fileWriter = new java.io.FileWriter(debuggerStartedFile);
fileWriter.write("started");
fileWriter.close();
}

// check if --debug-brk flag has been set. If positive:
// write to the file to invalidate the flag
// inform the v8Inspector to pause the main thread
File debugBreakFile = new File("/data/local/tmp", app.getPackageName() + "-debugbreak");
boolean shouldBreak = false;
if (debugBreakFile.exists() && !debugBreakFile.isDirectory() && debugBreakFile.length() == 0) {
java.io.FileWriter fileWriter = new java.io.FileWriter(debugBreakFile);
fileWriter.write("started");
fileWriter.close();

shouldBreak = true;
}

v8Inspector.waitForDebugger(shouldBreak);
} catch (IOException e) {
e.printStackTrace();
}
Expand Down
118 changes: 81 additions & 37 deletions runtime/src/main/java/com/tns/AndroidJsV8Inspector.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.List;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;

import fi.iki.elonen.NanoHTTPD;
import fi.iki.elonen.NanoWSD;
Expand All @@ -26,23 +27,32 @@ class AndroidJsV8Inspector {
private static boolean DEBUG_LOG_ENABLED = false;

private JsV8InspectorServer server;
private Context context;
private static String applicationDir;
private static String ApplicationDir;
private String packageName;

protected native final void init();

protected native final void connect(Object connection);

private native void scheduleBreak();

protected static native void disconnect();

protected native final void dispatchMessage(String message);

private Handler mainHandler;

private final Object debugBrkLock;

private static AtomicBoolean DebugInitialized = new AtomicBoolean(false);

private LinkedBlockingQueue<String> inspectorMessages = new LinkedBlockingQueue<String>();
private LinkedBlockingQueue<String> pendingInspectorMessages = new LinkedBlockingQueue<String>();

AndroidJsV8Inspector(Context context, Logger logger) {
this.context = context;
applicationDir = context.getFilesDir().getAbsolutePath();
AndroidJsV8Inspector(String filesDir, String packageName) {
ApplicationDir = filesDir;
this.packageName = packageName;
this.debugBrkLock = new Object();
}

public void start() throws IOException {
Expand All @@ -51,7 +61,7 @@ public void start() throws IOException {

mainHandler = currentRuntime.getHandler();

this.server = new JsV8InspectorServer(this.context.getPackageName() + "-inspectorServer");
this.server = new JsV8InspectorServer(this.packageName + "-inspectorServer");
this.server.start(-1);

if (DEBUG_LOG_ENABLED) {
Expand Down Expand Up @@ -82,9 +92,7 @@ private static void sendToDevToolsConsole(Object connection, String message, Str
String sendingText = consoleMessage.toString();
AndroidJsV8Inspector.send(connection, sendingText);

} catch (JSONException e) {
e.printStackTrace();
} catch (IOException e) {
} catch (JSONException | IOException e) {
e.printStackTrace();
}
}
Expand All @@ -102,11 +110,11 @@ private static String getInspectorMessage(Object connection) {
@RuntimeCallable
public static Pair<String, String>[] getPageResources() {
// necessary to align the data dir returned by context (emulator) and that used by the v8 inspector
if (applicationDir.startsWith("/data/user/0/")) {
applicationDir = applicationDir.replaceFirst("/data/user/0/", "/data/data/");
if (ApplicationDir.startsWith("/data/user/0/")) {
ApplicationDir = ApplicationDir.replaceFirst("/data/user/0/", "/data/data/");
}

String dataDir = applicationDir;
String dataDir = ApplicationDir;
File rootFilesDir = new File(dataDir, "app");


Expand Down Expand Up @@ -168,8 +176,41 @@ private static String getMimeType(String url) {
return type;
}

class JsV8InspectorServer extends NanoWSD {
public JsV8InspectorServer(String name) {
// pause the main thread for 30 seconds (30 * 1000 ms)
// allowing the devtools frontend to establish connection with the inspector
protected void waitForDebugger(boolean shouldBreak) {
if (shouldBreak) {
synchronized (this.debugBrkLock) {
try {
this.debugBrkLock.wait(1000 * 30);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
AndroidJsV8Inspector.DebugInitialized.getAndSet(true);
this.processDebugBreak();
}
}
} else {
AndroidJsV8Inspector.DebugInitialized.getAndSet(true);
}
}

// process all messages coming front the frontend necessary to initialize the inspector backend
// schedule a debug line break at first convenience
private void processDebugBreak() {
processDebugBreakMessages();
scheduleBreak();
}

private void processDebugBreakMessages() {
while (!pendingInspectorMessages.isEmpty()) {
String inspectorMessage = pendingInspectorMessages.poll();
dispatchMessage(inspectorMessage);
}
}

private class JsV8InspectorServer extends NanoWSD {
JsV8InspectorServer(String name) {
super(name);
}

Expand All @@ -187,9 +228,8 @@ protected WebSocket openWebSocket(IHTTPSession handshake) {
}
}

class JsV8InspectorWebSocket extends NanoWSD.WebSocket {

public JsV8InspectorWebSocket(NanoHTTPD.IHTTPSession handshakeRequest) {
private class JsV8InspectorWebSocket extends NanoWSD.WebSocket {
JsV8InspectorWebSocket(NanoHTTPD.IHTTPSession handshakeRequest) {
super(handshakeRequest);
}

Expand All @@ -199,16 +239,7 @@ protected void onOpen() {
Log.d("V8Inspector", "onOpen: ThreadID: " + Thread.currentThread().getId());
}

mainHandler.post(new Runnable() {
@Override
public void run() {
if (DEBUG_LOG_ENABLED) {
Log.d("V8Inspector", "Connecting. threadID : " + Thread.currentThread().getId());
}

connect(JsV8InspectorWebSocket.this);
}
});
connect(JsV8InspectorWebSocket.this);
}

@Override
Expand Down Expand Up @@ -236,16 +267,30 @@ protected void onMessage(final NanoWSD.WebSocketFrame message) {

inspectorMessages.offer(message.getTextPayload());

mainHandler.post(new Runnable() {
@Override
public void run() {
String nextMessage = inspectorMessages.poll();
while (nextMessage != null) {
dispatchMessage(nextMessage);
nextMessage = inspectorMessages.poll();
if (!AndroidJsV8Inspector.DebugInitialized.get()) {
String nextMessage = inspectorMessages.poll();
while (nextMessage != null) {
pendingInspectorMessages.offer(nextMessage);
nextMessage = inspectorMessages.poll();
}

if (message.getTextPayload().contains("Debugger.enable")) {
synchronized (debugBrkLock) {
debugBrkLock.notify();
}
}
});
} else {
mainHandler.postAtFrontOfQueue(new Runnable() {
@Override
public void run() {
String nextMessage = inspectorMessages.poll();
while (nextMessage != null) {
dispatchMessage(nextMessage);
nextMessage = inspectorMessages.poll();
}
}
});
}
}

@Override
Expand All @@ -259,8 +304,7 @@ public void send(String payload) throws IOException {

public String getInspectorMessage() {
try {
String message = inspectorMessages.take();
return message;
return inspectorMessages.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
Expand Down
7 changes: 7 additions & 0 deletions runtime/src/main/jni/JsV8InspectorClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ void JsV8InspectorClient::connect(jobject connection) {
this->isConnected = true;
}

void JsV8InspectorClient::scheduleBreak() {
Isolate::Scope isolate_scope(isolate_);
v8::HandleScope handleScope(isolate_);

this->session_->schedulePauseOnNextStatement(v8_inspector::StringView(), v8_inspector::StringView());
}

void JsV8InspectorClient::createInspectorSession(v8::Isolate* isolate, const v8::Local<v8::Context>& context) {
session_ = inspector_->connect(0, this, v8_inspector::StringView());
}
Expand Down
1 change: 1 addition & 0 deletions runtime/src/main/jni/JsV8InspectorClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class JsV8InspectorClient : V8InspectorClient, v8_inspector::V8Inspector::Channe

void init();
void connect(jobject connection);
void scheduleBreak();
void createInspectorSession(v8::Isolate* isolate, const v8::Local<v8::Context>& context);
void disconnect();
void dispatchMessage(const std::string& message);
Expand Down
4 changes: 4 additions & 0 deletions runtime/src/main/jni/com_tns_AndroidJsV8Inspector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ JNIEXPORT extern "C" void Java_com_tns_AndroidJsV8Inspector_connect(JNIEnv* env,
JsV8InspectorClient::GetInstance()->connect(connection);
}

JNIEXPORT extern "C" void Java_com_tns_AndroidJsV8Inspector_scheduleBreak(JNIEnv* env, jobject instance) {
JsV8InspectorClient::GetInstance()->scheduleBreak();
}

JNIEXPORT extern "C" void Java_com_tns_AndroidJsV8Inspector_disconnect(JNIEnv* env, jobject instance) {
JsV8InspectorClient::GetInstance()->disconnect();
}
Expand Down
19 changes: 17 additions & 2 deletions test-app/app/src/main/java/com/tns/RuntimeHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -132,17 +132,32 @@ public static Runtime initRuntime(Application app) {
runtime = Runtime.initializeRuntimeWithConfiguration(config);
if (isDebuggable) {
try {
v8Inspector = new AndroidJsV8Inspector(app, logger);
v8Inspector = new AndroidJsV8Inspector(app.getFilesDir().getAbsolutePath(), app.getPackageName());
v8Inspector.start();

// the following snippet is used as means to notify the VSCode extension
// debugger that the debugger agent has started
File debugBreakFile = new File("/data/local/tmp", app.getPackageName() + "-debugger-started");
File debuggerStartedFile = new File("/data/local/tmp", app.getPackageName() + "-debugger-started");
if (debuggerStartedFile.exists() && !debuggerStartedFile.isDirectory() && debuggerStartedFile.length() == 0) {
java.io.FileWriter fileWriter = new java.io.FileWriter(debuggerStartedFile);
fileWriter.write("started");
fileWriter.close();
}

// check if --debug-brk flag has been set. If positive:
// write to the file to invalidate the flag
// inform the v8Inspector to pause the main thread
File debugBreakFile = new File("/data/local/tmp", app.getPackageName() + "-debugbreak");
boolean shouldBreak = false;
if (debugBreakFile.exists() && !debugBreakFile.isDirectory() && debugBreakFile.length() == 0) {
java.io.FileWriter fileWriter = new java.io.FileWriter(debugBreakFile);
fileWriter.write("started");
fileWriter.close();

shouldBreak = true;
}

v8Inspector.waitForDebugger(shouldBreak);
} catch (IOException e) {
e.printStackTrace();
}
Expand Down