11320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Copyright 2014 The Chromium Authors. All rights reserved. 21320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Use of this source code is governed by a BSD-style license that can be 31320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// found in the LICENSE file. 41320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccipackage org.chromium.components.devtools_bridge; 61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport android.net.LocalSocket; 81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport android.net.LocalSocketAddress; 91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.io.IOException; 111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.util.concurrent.Callable; 121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.util.concurrent.CountDownLatch; 131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.util.concurrent.ExecutorService; 141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.util.concurrent.Executors; 151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.util.concurrent.Future; 161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/** 181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Utilities to testing a socket tunnel. 191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */ 201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccipublic class TestUtils { 211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private static final String CHARSET = "UTF-8"; 221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Sends |request| string to UNIX socket socketName on another thread and returns 241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Future<String> for obtainings response. 251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public static Future<String> asyncRequest(final String socketName, final String request) { 261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci final ExecutorService executor = Executors.newSingleThreadExecutor(); 281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return executor.submit(new Callable<String>() { 301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci @Override 311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public String call() throws Exception { 321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci LocalSocket socket = new LocalSocket(); 331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci socket.connect(new LocalSocketAddress(socketName)); 341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci writeAndShutdown(socket, request); 351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci String response = readAll(socket); 371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci socket.close(); 381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci executor.shutdown(); 401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return response; 411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci }); 431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public static void writeAndShutdown(LocalSocket socket, String data) throws IOException { 461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci socket.getOutputStream().write(data.getBytes(CHARSET)); 471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci socket.getOutputStream().flush(); 481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci socket.shutdownOutput(); 491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Reads all bytes from socket input stream until EOF and converts it to UTF-8 string. 521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public static String readAll(LocalSocket socket) throws IOException { 531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci byte[] buffer = new byte[1000]; 541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int position = 0; 551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci while (true) { 561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int count = socket.getInputStream().read(buffer, position, buffer.length - position); 571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (count == -1) 581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci break; 591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci position += count; 601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return new String(buffer, 0, position, CHARSET); 621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci /** 651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Utility class for thread synchronization. Allow to track moving through series of steps. 661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */ 671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public static class StateBarrier<T> { 681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private T mState; 691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private final Object mLock = new Object(); 701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public StateBarrier(T initialState) { 721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mState = initialState; 731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Waits until state |from| reached and change state to |to|. 761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public void advance(T from, T to) { 771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci synchronized (mLock) { 781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci while (mState.equals(from)) { 791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci try { 801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mLock.wait(); 811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } catch (InterruptedException e) { 821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci throw new RuntimeException(e); 831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mState = to; 861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mLock.notifyAll(); 871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci /** 921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Helper with runs code on another thread and synchronously take the result. 931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */ 941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public static class InvokeHelper<T> { 951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private final CountDownLatch mDone = new CountDownLatch(1); 961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private T mResult = null; 981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private Exception mException = null; 991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public void runOnTargetThread(Callable<T> callable) { 1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci try { 1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mResult = callable.call(); 1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } catch (Exception e) { 1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mException = e; 1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mDone.countDown(); 1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public T takeResult() throws Exception { 1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mDone.await(); 1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (mException != null) 1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci throw mException; 1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci else 1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return mResult; 1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci /** 1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Adapts Runnable to Callable<Void>. 1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */ 1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public static class RunnableAdapter implements Callable<Void> { 1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private final Runnable mAdaptee; 1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public RunnableAdapter(Runnable adaptee) { 1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mAdaptee = adaptee; 1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci @Override 1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public Void call() { 1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mAdaptee.run(); 1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return null; 1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 135