refactor(debug): 从DebugToolFragment中分离debug逻辑

This commit is contained in:
hyb1996
2018-09-11 08:11:59 +08:00
parent 0b84d755dc
commit 834280428d
12 changed files with 764 additions and 121 deletions

View File

@@ -1,20 +1,5 @@
package com.stardust.autojs.rhino.debug;
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import com.stardust.autojs.engine.RhinoJavaScriptEngine;
import com.stardust.autojs.engine.ScriptEngine;
import org.mozilla.javascript.Context;
/**
* Interface for communication between the debugger and its GUI. This
* should be implemented by the GUI.
*/
public interface DebugCallback {
/**
@@ -29,22 +14,4 @@ public interface DebugCallback {
String threadTitle,
String alertMessage);
/**
* Returns whether the current thread is the GUI's event thread.
* This information is required to avoid blocking the event thread
* from the debugger.
*/
boolean isGuiEventThread();
/**
* Processes the next GUI event. This manual pumping of GUI events
* is necessary when the GUI event thread itself has been stopped.
*/
void dispatchNextGuiEvent() throws InterruptedException;
/**
*
* Returns whether the debugger should attach to this engine or not.
*/
boolean shouldAttachDebugger(RhinoJavaScriptEngine engine);
}
}

View File

@@ -0,0 +1,49 @@
package com.stardust.autojs.rhino.debug;
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import com.stardust.autojs.engine.RhinoJavaScriptEngine;
import com.stardust.autojs.engine.ScriptEngine;
import org.mozilla.javascript.Context;
/**
* Interface for communication between the debugger and its GUI. This
* should be implemented by the GUI.
*/
interface DebugCallbackInternal {
/**
* Called when the source text of some script has been changed.
*/
void updateSourceText(Dim.SourceInfo sourceInfo);
/**
* Called when the interrupt loop has been entered.
*/
void enterInterrupt(Dim.StackFrame lastFrame,
String threadTitle,
String alertMessage);
/**
* Returns whether the current thread is the GUI's event thread.
* This information is required to avoid blocking the event thread
* from the debugger.
*/
boolean isGuiEventThread();
/**
* Processes the next GUI event. This manual pumping of GUI events
* is necessary when the GUI event thread itself has been stopped.
*/
void dispatchNextGuiEvent() throws InterruptedException;
/**
* Returns whether the debugger should attach to this engine or not.
*/
boolean shouldAttachDebugger(RhinoJavaScriptEngine engine);
}

View File

@@ -0,0 +1,163 @@
package com.stardust.autojs.rhino.debug;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.Nullable;
import android.util.Log;
import com.stardust.autojs.ScriptEngineService;
import com.stardust.autojs.engine.RhinoJavaScriptEngine;
import com.stardust.autojs.execution.ScriptExecution;
import org.mozilla.javascript.ContextFactory;
import java.lang.ref.WeakReference;
public class Debugger implements DebugCallbackInternal {
private static final String LOG_TAG = "Debugger";
private final ScriptEngineService mScriptEngineService;
private final ContextFactory mContextFactory;
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final Dim mDim = createDim();
private DebugCallback mDebugCallback;
private boolean mSkipOtherFileBreakpoint = false;
@Nullable
private String mSourceUrl;
@Nullable
private ScriptExecution mScriptExecution;
@Nullable
private Dim.SourceInfo mSourceInfo;
private WeakReference<DebugCallback> mWeakDebugCallback;
public Debugger(ScriptEngineService scriptEngineService, ContextFactory contextFactory) {
mScriptEngineService = scriptEngineService;
mContextFactory = contextFactory;
}
public void attach(ScriptExecution execution) {
if(isAttached()){
detach();
}
mScriptExecution = execution;
mSkipOtherFileBreakpoint = true;
mSourceUrl = execution.getSource().toString();
mDim.attachTo(mScriptEngineService, mContextFactory);
}
@Override
public void updateSourceText(Dim.SourceInfo sourceInfo) {
if (!sourceInfo.url().equals(mSourceUrl)) {
return;
}
mSourceInfo = sourceInfo;
if(mDebugCallback != null){
mDebugCallback.updateSourceText(sourceInfo);
}
DebugCallback callback = mWeakDebugCallback == null ? null : mWeakDebugCallback.get();
if(callback != null){
callback.updateSourceText(sourceInfo);
}
}
@Override
public void enterInterrupt(Dim.StackFrame lastFrame, String threadTitle, String alertMessage) {
Log.d(LOG_TAG, "enterInterrupt: threadName = " + threadTitle + ", url = " + lastFrame.getUrl() + ", line = " + lastFrame.getLineNumber());
//刚启动调试时会在init脚本的第一行自动停下此时应该让脚本继续运行
if (mSkipOtherFileBreakpoint && !lastFrame.getUrl().equals(mSourceUrl) && alertMessage == null) {
mHandler.post(this::resume);
return;
}
mSkipOtherFileBreakpoint = false;
if(mDebugCallback != null){
mDebugCallback.enterInterrupt(lastFrame, threadTitle, alertMessage);
}
DebugCallback callback = mWeakDebugCallback == null ? null : mWeakDebugCallback.get();
if(callback != null){
callback.enterInterrupt(lastFrame, threadTitle, alertMessage);
}
}
@Override
public boolean isGuiEventThread() {
return Looper.getMainLooper() == Looper.myLooper();
}
@Override
public void dispatchNextGuiEvent() {
}
@Override
public boolean shouldAttachDebugger(RhinoJavaScriptEngine engine) {
return mScriptExecution != null && mScriptExecution.getId() == engine.getId();
}
public void breakpoint(int line, boolean enabled) {
if (mSourceInfo != null) {
mSourceInfo.breakpoint(line, enabled);
}
}
private Dim createDim() {
Dim dim = new Dim();
dim.setBreak();
dim.setBreakOnExceptions(true);
dim.setGuiCallback(this);
return dim;
}
public void resume() {
mDim.setReturnValue(Dim.GO);
}
public void stepOut() {
mDim.setReturnValue(Dim.STEP_OUT);
}
public void stepInto() {
mDim.setReturnValue(Dim.STEP_INTO);
}
public void stepOver() {
mDim.setReturnValue(Dim.STEP_OVER);
}
public boolean isAttached() {
return mDim.isAttached();
}
public String eval(String expr) {
if (expr == null || !mDim.isAttached() || !mDim.stringIsCompilableUnit(expr)) {
return null;
}
mDim.contextSwitch(0);
return mDim.eval(expr);
}
public void clearAllBreakpoints() {
mDim.clearAllBreakpoints();
}
public void detach() {
mDim.detach();
mScriptExecution = null;
mSourceUrl = null;
mSourceInfo = null;
}
public void setDebugCallback(DebugCallback debugCallback) {
mDebugCallback = debugCallback;
}
public void setWeakDebugCallback(WeakReference<DebugCallback> debugCallback) {
mWeakDebugCallback = debugCallback;
}
}

View File

@@ -14,6 +14,7 @@ import com.stardust.autojs.engine.ScriptEngineManager;
import org.mozilla.javascript.*;
import org.mozilla.javascript.debug.*;
import org.mozilla.javascript.tools.debugger.*;
import org.mozilla.javascript.debug.Debugger;
import java.util.*;
import java.io.*;
@@ -47,7 +48,7 @@ public class Dim {
/**
* Interface to the debugger GUI.
*/
private DebugCallback callback;
private DebugCallbackInternal callback;
/**
* Whether the debugger should break.
@@ -162,7 +163,7 @@ public class Dim {
/**
* Sets the GuiCallback object to use.
*/
public void setGuiCallback(DebugCallback callback) {
public void setGuiCallback(DebugCallbackInternal callback) {
this.callback = callback;
}