1818import java .util .List ;
1919import java .util .Queue ;
2020import java .util .concurrent .LinkedBlockingQueue ;
21+ import java .util .concurrent .atomic .AtomicBoolean ;
2122
2223import fi .iki .elonen .NanoHTTPD ;
2324import fi .iki .elonen .NanoWSD ;
@@ -26,23 +27,32 @@ class AndroidJsV8Inspector {
2627 private static boolean DEBUG_LOG_ENABLED = false ;
2728
2829 private JsV8InspectorServer server ;
29- private Context context ;
30- private static String applicationDir ;
30+ private static String ApplicationDir ;
31+ private String packageName ;
3132
3233 protected native final void init ();
3334
3435 protected native final void connect (Object connection );
3536
37+ private native void scheduleBreak ();
38+
3639 protected static native void disconnect ();
3740
3841 protected native final void dispatchMessage (String message );
3942
4043 private Handler mainHandler ;
44+
45+ private final Object debugBrkLock ;
46+
47+ private static AtomicBoolean DebugInitialized = new AtomicBoolean (false );
48+
4149 private LinkedBlockingQueue <String > inspectorMessages = new LinkedBlockingQueue <String >();
50+ private LinkedBlockingQueue <String > pendingInspectorMessages = new LinkedBlockingQueue <String >();
4251
43- AndroidJsV8Inspector (Context context , Logger logger ) {
44- this .context = context ;
45- applicationDir = context .getFilesDir ().getAbsolutePath ();
52+ AndroidJsV8Inspector (String filesDir , String packageName ) {
53+ ApplicationDir = filesDir ;
54+ this .packageName = packageName ;
55+ this .debugBrkLock = new Object ();
4656 }
4757
4858 public void start () throws IOException {
@@ -51,7 +61,7 @@ public void start() throws IOException {
5161
5262 mainHandler = currentRuntime .getHandler ();
5363
54- this .server = new JsV8InspectorServer (this .context . getPackageName () + "-inspectorServer" );
64+ this .server = new JsV8InspectorServer (this .packageName + "-inspectorServer" );
5565 this .server .start (-1 );
5666
5767 if (DEBUG_LOG_ENABLED ) {
@@ -82,9 +92,7 @@ private static void sendToDevToolsConsole(Object connection, String message, Str
8292 String sendingText = consoleMessage .toString ();
8393 AndroidJsV8Inspector .send (connection , sendingText );
8494
85- } catch (JSONException e ) {
86- e .printStackTrace ();
87- } catch (IOException e ) {
95+ } catch (JSONException | IOException e ) {
8896 e .printStackTrace ();
8997 }
9098 }
@@ -102,11 +110,11 @@ private static String getInspectorMessage(Object connection) {
102110 @ RuntimeCallable
103111 public static Pair <String , String >[] getPageResources () {
104112 // necessary to align the data dir returned by context (emulator) and that used by the v8 inspector
105- if (applicationDir .startsWith ("/data/user/0/" )) {
106- applicationDir = applicationDir .replaceFirst ("/data/user/0/" , "/data/data/" );
113+ if (ApplicationDir .startsWith ("/data/user/0/" )) {
114+ ApplicationDir = ApplicationDir .replaceFirst ("/data/user/0/" , "/data/data/" );
107115 }
108116
109- String dataDir = applicationDir ;
117+ String dataDir = ApplicationDir ;
110118 File rootFilesDir = new File (dataDir , "app" );
111119
112120
@@ -168,8 +176,41 @@ private static String getMimeType(String url) {
168176 return type ;
169177 }
170178
171- class JsV8InspectorServer extends NanoWSD {
172- public JsV8InspectorServer (String name ) {
179+ // pause the main thread for 30 seconds (30 * 1000 ms)
180+ // allowing the devtools frontend to establish connection with the inspector
181+ protected void waitForDebugger (boolean shouldBreak ) {
182+ if (shouldBreak ) {
183+ synchronized (this .debugBrkLock ) {
184+ try {
185+ this .debugBrkLock .wait (1000 * 30 );
186+ } catch (InterruptedException e ) {
187+ e .printStackTrace ();
188+ } finally {
189+ AndroidJsV8Inspector .DebugInitialized .getAndSet (true );
190+ this .processDebugBreak ();
191+ }
192+ }
193+ } else {
194+ AndroidJsV8Inspector .DebugInitialized .getAndSet (true );
195+ }
196+ }
197+
198+ // process all messages coming front the frontend necessary to initialize the inspector backend
199+ // schedule a debug line break at first convenience
200+ private void processDebugBreak () {
201+ processDebugBreakMessages ();
202+ scheduleBreak ();
203+ }
204+
205+ private void processDebugBreakMessages () {
206+ while (!pendingInspectorMessages .isEmpty ()) {
207+ String inspectorMessage = pendingInspectorMessages .poll ();
208+ dispatchMessage (inspectorMessage );
209+ }
210+ }
211+
212+ private class JsV8InspectorServer extends NanoWSD {
213+ JsV8InspectorServer (String name ) {
173214 super (name );
174215 }
175216
@@ -187,9 +228,8 @@ protected WebSocket openWebSocket(IHTTPSession handshake) {
187228 }
188229 }
189230
190- class JsV8InspectorWebSocket extends NanoWSD .WebSocket {
191-
192- public JsV8InspectorWebSocket (NanoHTTPD .IHTTPSession handshakeRequest ) {
231+ private class JsV8InspectorWebSocket extends NanoWSD .WebSocket {
232+ JsV8InspectorWebSocket (NanoHTTPD .IHTTPSession handshakeRequest ) {
193233 super (handshakeRequest );
194234 }
195235
@@ -199,16 +239,7 @@ protected void onOpen() {
199239 Log .d ("V8Inspector" , "onOpen: ThreadID: " + Thread .currentThread ().getId ());
200240 }
201241
202- mainHandler .post (new Runnable () {
203- @ Override
204- public void run () {
205- if (DEBUG_LOG_ENABLED ) {
206- Log .d ("V8Inspector" , "Connecting. threadID : " + Thread .currentThread ().getId ());
207- }
208-
209- connect (JsV8InspectorWebSocket .this );
210- }
211- });
242+ connect (JsV8InspectorWebSocket .this );
212243 }
213244
214245 @ Override
@@ -236,16 +267,30 @@ protected void onMessage(final NanoWSD.WebSocketFrame message) {
236267
237268 inspectorMessages .offer (message .getTextPayload ());
238269
239- mainHandler .post (new Runnable () {
240- @ Override
241- public void run () {
242- String nextMessage = inspectorMessages .poll ();
243- while (nextMessage != null ) {
244- dispatchMessage (nextMessage );
245- nextMessage = inspectorMessages .poll ();
270+ if (!AndroidJsV8Inspector .DebugInitialized .get ()) {
271+ String nextMessage = inspectorMessages .poll ();
272+ while (nextMessage != null ) {
273+ pendingInspectorMessages .offer (nextMessage );
274+ nextMessage = inspectorMessages .poll ();
275+ }
276+
277+ if (message .getTextPayload ().contains ("Debugger.enable" )) {
278+ synchronized (debugBrkLock ) {
279+ debugBrkLock .notify ();
246280 }
247281 }
248- });
282+ } else {
283+ mainHandler .postAtFrontOfQueue (new Runnable () {
284+ @ Override
285+ public void run () {
286+ String nextMessage = inspectorMessages .poll ();
287+ while (nextMessage != null ) {
288+ dispatchMessage (nextMessage );
289+ nextMessage = inspectorMessages .poll ();
290+ }
291+ }
292+ });
293+ }
249294 }
250295
251296 @ Override
@@ -259,8 +304,7 @@ public void send(String payload) throws IOException {
259304
260305 public String getInspectorMessage () {
261306 try {
262- String message = inspectorMessages .take ();
263- return message ;
307+ return inspectorMessages .take ();
264308 } catch (InterruptedException e ) {
265309 e .printStackTrace ();
266310 }
0 commit comments