Lint source code to AOSP. (#34)

* Add linter for the project.
* Apply AOSP style.
* Bump gradle toolchain version.
* Remove unused code.
* Fix quotation mark usage.
diff --git a/build.gradle b/build.gradle
index 53f4fad..74b2ab0 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,7 +5,7 @@
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.1'
+        classpath 'com.android.tools.build:gradle:2.2.3'
 
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files
diff --git a/third_party/sl4a/build.gradle b/third_party/sl4a/build.gradle
index a5d54db..f5c82ae 100644
--- a/third_party/sl4a/build.gradle
+++ b/third_party/sl4a/build.gradle
@@ -8,13 +8,17 @@
     }
 }
 
+plugins {
+    id 'com.github.sherter.google-java-format' version '0.6'
+}
+
 apply plugin: 'com.android.library'
 apply plugin: 'com.jfrog.bintray'
 apply plugin: 'com.github.dcendents.android-maven'
 
 android {
     compileSdkVersion 24
-    buildToolsVersion "24.0.3"
+    buildToolsVersion '24.0.3'
 
     defaultConfig {
         minSdkVersion 11
@@ -32,6 +36,10 @@
     compile 'com.android.support.test:runner:0.5'
 }
 
+googleJavaFormat {
+    options style: 'AOSP'
+}
+
 task sourcesJar(type: Jar) {
     from android.sourceSets.main.java.srcDirs
     classifier = 'sources'
@@ -103,10 +111,10 @@
             if (bintrayPropFile.exists()) {
                 throw new IllegalArgumentException(
                     bintrayPropFile.toString()
-                    + " does not contain 'user' or 'key' props")
+                    + ' does not contain "user" or "key" props')
             } else {
                 throw new FileNotFoundException(
-                    "bintray.properties not found at path: " + bintrayPropFile)
+                    'bintray.properties not found at path: ' + bintrayPropFile)
             }
         }
     }
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/Snippet.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/Snippet.java
index fb3a1b9..b560a20 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/Snippet.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/Snippet.java
@@ -17,6 +17,6 @@
 package com.google.android.mobly.snippet;
 
 public interface Snippet {
-  /** Invoked when the receiver is shut down. */
-  void shutdown();
+    /** Invoked when the receiver is shut down. */
+    void shutdown();
 }
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/SnippetRunner.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/SnippetRunner.java
index aa51009..16e006e 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/SnippetRunner.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/SnippetRunner.java
@@ -21,7 +21,6 @@
 import android.os.Bundle;
 import android.os.Process;
 import android.support.test.runner.AndroidJUnitRunner;
-
 import com.google.android.mobly.snippet.rpc.AndroidProxy;
 import com.google.android.mobly.snippet.util.EmptyTestClass;
 import com.google.android.mobly.snippet.util.Log;
@@ -34,15 +33,18 @@
  * target app's context.
  *
  * <p>We have to extend some subclass of {@link android.test.InstrumentationTestRunner} because
- * snippets are launched with 'am instrument'. We're specifically extending
- * {@link AndroidJUnitRunner} because Espresso requires being called through it, since it sets up
- * {@link android.support.test.InstrumentationRegistry} which Espresso requires.
+ * snippets are launched with 'am instrument'. We're specifically extending {@link
+ * AndroidJUnitRunner} because Espresso requires being called through it, since it sets up {@link
+ * android.support.test.InstrumentationRegistry} which Espresso requires.
  */
 public class SnippetRunner extends AndroidJUnitRunner {
     private static final String ARG_ACTION = "action";
     private static final String ARG_PORT = "port";
 
-    private enum Action {START, STOP};
+    private enum Action {
+        START,
+        STOP
+    };
 
     private static final int NOTIFICATION_ID = NotificationIdFactory.create();
 
@@ -56,8 +58,9 @@
         // Prevent this runner from triggering any real JUnit tests in the snippet by feeding it a
         // hardcoded empty test class.
         mArguments.putString("class", EmptyTestClass.class.getCanonicalName());
-        mNotificationManager = (NotificationManager)
-                getTargetContext().getSystemService(Context.NOTIFICATION_SERVICE);
+        mNotificationManager =
+                (NotificationManager)
+                        getTargetContext().getSystemService(Context.NOTIFICATION_SERVICE);
         super.onCreate(mArguments);
     }
 
@@ -69,18 +72,18 @@
         }
         Action action = Action.valueOf(actionStr.toUpperCase());
         switch (action) {
-        case START:
-            String servicePort = mArguments.getString(ARG_PORT);
-            if (servicePort == null) {
-                throw new IllegalArgumentException("\"--e port <port>\" was not specified");
-            }
-            int port = Integer.parseInt(servicePort);
-            startServer(port);
-            break;
-        case STOP:
-            mNotificationManager.cancel(NOTIFICATION_ID);
-            mNotificationManager.cancelAll();
-            super.onStart();
+            case START:
+                String servicePort = mArguments.getString(ARG_PORT);
+                if (servicePort == null) {
+                    throw new IllegalArgumentException("\"--e port <port>\" was not specified");
+                }
+                int port = Integer.parseInt(servicePort);
+                startServer(port);
+                break;
+            case STOP:
+                mNotificationManager.cancel(NOTIFICATION_ID);
+                mNotificationManager.cancelAll();
+                super.onStart();
         }
     }
 
@@ -90,9 +93,12 @@
             androidProxy.startLocal(port);
         } catch (SocketException e) {
             if (e.getMessage().equals("Permission denied")) {
-                throw new RuntimeException("Failed to start server on port "
-                    + port + ". No permission to create a socket. Does the *MAIN* app manifest "
-                    + "declare the INTERNET permission?", e);
+                throw new RuntimeException(
+                        "Failed to start server on port "
+                                + port
+                                + ". No permission to create a socket. Does the *MAIN* app manifest "
+                                + "declare the INTERNET permission?",
+                        e);
             }
             throw new RuntimeException("Failed to start server on port " + port, e);
         } catch (IOException e) {
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/future/FutureResult.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/future/FutureResult.java
index 9533f26..5e6edd3 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/future/FutureResult.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/future/FutureResult.java
@@ -20,10 +20,7 @@
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 
-/**
- * FutureResult represents an eventual execution result for asynchronous operations.
- *
- */
+/** FutureResult represents an eventual execution result for asynchronous operations. */
 public class FutureResult<T> implements Future<T> {
 
     private final CountDownLatch mLatch = new CountDownLatch(1);
@@ -60,5 +57,4 @@
     public boolean isDone() {
         return mResult != null;
     }
-
 }
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/manager/ReflectionSnippetManagerFactory.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/manager/ReflectionSnippetManagerFactory.java
index eb97481..db90f32 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/manager/ReflectionSnippetManagerFactory.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/manager/ReflectionSnippetManagerFactory.java
@@ -21,10 +21,8 @@
 import android.content.pm.PackageManager;
 import android.os.Build;
 import android.os.Bundle;
-
 import com.google.android.mobly.snippet.Snippet;
 import com.google.android.mobly.snippet.util.Log;
-
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -60,9 +58,10 @@
     private Set<Class<? extends Snippet>> loadSnippets() {
         ApplicationInfo appInfo;
         try {
-            appInfo = mContext
-                    .getPackageManager()
-                    .getApplicationInfo(mContext.getPackageName(), PackageManager.GET_META_DATA);
+            appInfo =
+                    mContext.getPackageManager()
+                            .getApplicationInfo(
+                                    mContext.getPackageName(), PackageManager.GET_META_DATA);
         } catch (PackageManager.NameNotFoundException e) {
             throw new IllegalStateException(
                     "Failed to find ApplicationInfo with package name: "
@@ -73,7 +72,9 @@
         if (snippets == null) {
             throw new IllegalStateException(
                     "AndroidManifest.xml does not contain a <metadata> tag with "
-                        + "name=\"" + METADATA_TAG_NAME + "\"");
+                            + "name=\""
+                            + METADATA_TAG_NAME
+                            + "\"");
         }
         String[] snippetClassNames = snippets.split("\\s*,\\s*");
         Set<Class<? extends Snippet>> receiverSet = new HashSet<>();
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/manager/SnippetManager.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/manager/SnippetManager.java
index e27c473..da5a56d 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/manager/SnippetManager.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/manager/SnippetManager.java
@@ -17,7 +17,11 @@
 package com.google.android.mobly.snippet.manager;
 
 import android.os.Build;
-
+import com.google.android.mobly.snippet.Snippet;
+import com.google.android.mobly.snippet.rpc.MethodDescriptor;
+import com.google.android.mobly.snippet.rpc.RpcMinSdk;
+import com.google.android.mobly.snippet.util.Log;
+import com.google.android.mobly.snippet.util.SnippetLibException;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -27,16 +31,11 @@
 import java.util.SortedSet;
 import java.util.TreeSet;
 
-import com.google.android.mobly.snippet.Snippet;
-import com.google.android.mobly.snippet.rpc.MethodDescriptor;
-import com.google.android.mobly.snippet.rpc.RpcMinSdk;
-import com.google.android.mobly.snippet.util.Log;
-import com.google.android.mobly.snippet.util.SnippetLibException;
-
 public class SnippetManager {
     private final Map<Class<? extends Snippet>, Snippet> mReceivers;
     /** A map of strings to known RPCs. */
-    private final Map<String, MethodDescriptor> mKnownRpcs = new HashMap<String, MethodDescriptor>();
+    private final Map<String, MethodDescriptor> mKnownRpcs =
+            new HashMap<String, MethodDescriptor>();
 
     public SnippetManager(Collection<Class<? extends Snippet>> classList) {
         mReceivers = new HashMap<>();
@@ -47,8 +46,8 @@
                 if (mKnownRpcs.containsKey(m.getName())) {
                     // We already know an RPC of the same name. We don't catch this anywhere because
                     // this is a programming error.
-                    throw new RuntimeException("An RPC with the name " + m.getName()
-                            + " is already known.");
+                    throw new RuntimeException(
+                            "An RPC with the name " + m.getName() + " is already known.");
                 }
                 mKnownRpcs.put(m.getName(), m);
             }
@@ -69,7 +68,8 @@
             int requiredSdkLevel = method.getAnnotation(RpcMinSdk.class).value();
             if (Build.VERSION.SDK_INT < requiredSdkLevel) {
                 throw new SnippetLibException(
-                        String.format("%s requires API level %d, current level is %d",
+                        String.format(
+                                "%s requires API level %d, current level is %d",
                                 method.getName(), requiredSdkLevel, Build.VERSION.SDK_INT));
             }
         }
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/manager/SnippetManagerFactory.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/manager/SnippetManagerFactory.java
index 9acb273..50a3552 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/manager/SnippetManagerFactory.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/manager/SnippetManagerFactory.java
@@ -19,6 +19,7 @@
 import java.util.Map;
 
 public interface SnippetManagerFactory {
-  SnippetManager create(Integer UID);
-  Map<Integer, SnippetManager> getSnippetManagers();
+    SnippetManager create(Integer UID);
+
+    Map<Integer, SnippetManager> getSnippetManagers();
 }
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/AndroidProxy.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/AndroidProxy.java
index de122c6..6434814 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/AndroidProxy.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/AndroidProxy.java
@@ -17,12 +17,9 @@
 package com.google.android.mobly.snippet.rpc;
 
 import android.content.Context;
-
 import com.google.android.mobly.snippet.manager.ReflectionSnippetManagerFactory;
 import com.google.android.mobly.snippet.manager.SnippetManagerFactory;
-
 import java.io.IOException;
-import java.net.InetSocketAddress;
 
 public class AndroidProxy {
 
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/JsonBuilder.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/JsonBuilder.java
index 6c922b4..d005530 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/JsonBuilder.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/JsonBuilder.java
@@ -16,6 +16,11 @@
 
 package com.google.android.mobly.snippet.rpc;
 
+import android.content.ComponentName;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.ParcelUuid;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.URL;
@@ -25,17 +30,10 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
-
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
-import android.content.ComponentName;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.ParcelUuid;
-
 public class JsonBuilder {
 
     @SuppressWarnings("unchecked")
@@ -140,8 +138,7 @@
         return result;
     }
 
-    private static JSONObject buildJsonBundle(Bundle bundle)
-            throws JSONException {
+    private static JSONObject buildJsonBundle(Bundle bundle) throws JSONException {
         JSONObject result = new JSONObject();
         for (String key : bundle.keySet()) {
             result.put(key, build(bundle.get(key)));
@@ -165,8 +162,7 @@
         return result;
     }
 
-    private static <T> JSONArray buildJsonList(final List<T> list)
-            throws JSONException {
+    private static <T> JSONArray buildJsonList(final List<T> list) throws JSONException {
         JSONArray result = new JSONArray();
         for (T item : list) {
             result.put(build(item));
@@ -174,8 +170,7 @@
         return result;
     }
 
-    private static JSONObject buildJsonMap(Map<String, ?> map)
-            throws JSONException {
+    private static JSONObject buildJsonMap(Map<String, ?> map) throws JSONException {
         JSONObject result = new JSONObject();
         for (Entry<String, ?> entry : map.entrySet()) {
             String key = entry.getKey();
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/JsonRpcResult.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/JsonRpcResult.java
index ce02344..739eadf 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/JsonRpcResult.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/JsonRpcResult.java
@@ -25,41 +25,40 @@
  * Represents a JSON RPC result.
  *
  * @see http://json-rpc.org/wiki/specification
- *
  */
 public class JsonRpcResult {
 
-  private JsonRpcResult() {
-    // Utility class.
-  }
+    private JsonRpcResult() {
+        // Utility class.
+    }
 
-  public static JSONObject empty(int id) throws JSONException {
-    JSONObject json = new JSONObject();
-    json.put("id", id);
-    json.put("result", JSONObject.NULL);
-    json.put("error", JSONObject.NULL);
-    return json;
-  }
+    public static JSONObject empty(int id) throws JSONException {
+        JSONObject json = new JSONObject();
+        json.put("id", id);
+        json.put("result", JSONObject.NULL);
+        json.put("error", JSONObject.NULL);
+        return json;
+    }
 
-  public static JSONObject result(int id, Object data) throws JSONException {
-    JSONObject json = new JSONObject();
-    json.put("id", id);
-    json.put("result", JsonBuilder.build(data));
-    json.put("error", JSONObject.NULL);
-    return json;
-  }
+    public static JSONObject result(int id, Object data) throws JSONException {
+        JSONObject json = new JSONObject();
+        json.put("id", id);
+        json.put("result", JsonBuilder.build(data));
+        json.put("error", JSONObject.NULL);
+        return json;
+    }
 
-  public static JSONObject error(int id, Throwable t) throws JSONException {
-    StringWriter stackTraceWriter = new StringWriter();
-    stackTraceWriter.write("\n-------------- Java Stacktrace ---------------\n");
-    t.printStackTrace(new PrintWriter(stackTraceWriter));
-    stackTraceWriter.write("----------------------------------------------");
-    String stackTrace = stackTraceWriter.toString();
+    public static JSONObject error(int id, Throwable t) throws JSONException {
+        StringWriter stackTraceWriter = new StringWriter();
+        stackTraceWriter.write("\n-------------- Java Stacktrace ---------------\n");
+        t.printStackTrace(new PrintWriter(stackTraceWriter));
+        stackTraceWriter.write("----------------------------------------------");
+        String stackTrace = stackTraceWriter.toString();
 
-    JSONObject json = new JSONObject();
-    json.put("id", id);
-    json.put("result", JSONObject.NULL);
-    json.put("error", stackTrace);
-    return json;
-  }
+        JSONObject json = new JSONObject();
+        json.put("id", id);
+        json.put("result", JSONObject.NULL);
+        json.put("error", stackTrace);
+        return json;
+    }
 }
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/JsonRpcServer.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/JsonRpcServer.java
index a2af78b..6542aad 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/JsonRpcServer.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/JsonRpcServer.java
@@ -19,19 +19,15 @@
 import com.google.android.mobly.snippet.manager.SnippetManager;
 import com.google.android.mobly.snippet.manager.SnippetManagerFactory;
 import com.google.android.mobly.snippet.util.Log;
-
 import java.io.BufferedReader;
 import java.io.PrintWriter;
 import java.net.Socket;
 import java.util.Map;
-
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
-/**
- * A JSON RPC server that forwards RPC calls to a specified receiver object.
- */
+/** A JSON RPC server that forwards RPC calls to a specified receiver object. */
 public class JsonRpcServer extends SimpleServer {
     private static final String CMD_CLOSE_SESSION = "closeSl4aSession";
     private static final String CMD_HELP = "help";
@@ -57,14 +53,13 @@
     }
 
     @Override
-    protected void handleRPCConnection(Socket sock, Integer UID, BufferedReader reader,
-            PrintWriter writer) throws Exception {
+    protected void handleRPCConnection(
+            Socket sock, Integer UID, BufferedReader reader, PrintWriter writer) throws Exception {
         SnippetManager receiverManager = null;
         Map<Integer, SnippetManager> mgrs = mSnippetManagerFactory.getSnippetManagers();
         synchronized (mgrs) {
             Log.d("UID " + UID);
-            Log.d("manager map keys: "
-                    + mSnippetManagerFactory.getSnippetManagers().keySet());
+            Log.d("manager map keys: " + mSnippetManagerFactory.getSnippetManagers().keySet());
             if (mgrs.containsKey(UID)) {
                 Log.d("Look up existing session");
                 receiverManager = mgrs.get(UID);
@@ -114,7 +109,7 @@
     }
 
     private void help(PrintWriter writer, int id, SnippetManager receiverManager, Integer UID)
-        throws JSONException {
+            throws JSONException {
         StringBuilder result = new StringBuilder("Known methods:\n");
         for (String method : receiverManager.getMethodNames()) {
             MethodDescriptor descriptor = receiverManager.getMethodDescriptor(method);
@@ -130,6 +125,5 @@
     }
 
     @Override
-    protected void handleConnection(Socket socket) throws Exception {
-    }
+    protected void handleConnection(Socket socket) throws Exception {}
 }
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/MethodDescriptor.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/MethodDescriptor.java
index 862278e..c64fdd4 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/MethodDescriptor.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/MethodDescriptor.java
@@ -18,203 +18,202 @@
 
 import android.content.Intent;
 import android.net.Uri;
-
 import com.google.android.mobly.snippet.Snippet;
 import com.google.android.mobly.snippet.manager.SnippetManager;
 import com.google.android.mobly.snippet.util.AndroidUtil;
-
 import java.lang.reflect.Method;
 import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
-
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
-/**
- * An adapter that wraps {@code Method}.
- *
- */
+/** An adapter that wraps {@code Method}. */
 public final class MethodDescriptor {
-  private final Method mMethod;
-  private final Class<? extends Snippet> mClass;
+    private final Method mMethod;
+    private final Class<? extends Snippet> mClass;
 
-  public MethodDescriptor(Class<? extends Snippet> clazz, Method method) {
-    mClass = clazz;
-    mMethod = method;
-  }
-
-  @Override
-  public String toString() {
-    return mMethod.getDeclaringClass().getCanonicalName() + "." + mMethod.getName();
-  }
-
-  /** Collects all methods with {@code RPC} annotation from given class. */
-  public static Collection<MethodDescriptor> collectFrom(Class<? extends Snippet> clazz) {
-    List<MethodDescriptor> descriptors = new ArrayList<MethodDescriptor>();
-    for (Method method : clazz.getMethods()) {
-      if (method.isAnnotationPresent(Rpc.class)) {
-        descriptors.add(new MethodDescriptor(clazz, method));
-      }
-    }
-    return descriptors;
-  }
-
-  /**
-   * Invokes the call that belongs to this object with the given parameters. Wraps the response
-   * (possibly an exception) in a JSONObject.
-   *
-   * @param parameters
-   *          {@code JSONArray} containing the parameters
-   * @return result
-   * @throws Throwable
-   */
-  public Object invoke(SnippetManager manager, final JSONArray parameters) throws Throwable {
-    final Type[] parameterTypes = getGenericParameterTypes();
-    final Object[] args = new Object[parameterTypes.length];
-
-    if (parameters.length() > args.length) {
-      throw new RpcError("Too many parameters specified.");
+    public MethodDescriptor(Class<? extends Snippet> clazz, Method method) {
+        mClass = clazz;
+        mMethod = method;
     }
 
-    for (int i = 0; i < args.length; i++) {
-      final Type parameterType = parameterTypes[i];
-      if (i < parameters.length()) {
-        args[i] = convertParameter(parameters, i, parameterType);
-      } else {
-        throw new RpcError("Argument " + (i + 1) + " is not present");
-      }
+    @Override
+    public String toString() {
+        return mMethod.getDeclaringClass().getCanonicalName() + "." + mMethod.getName();
     }
 
-    return manager.invoke(mClass, mMethod, args);
-  }
+    /** Collects all methods with {@code RPC} annotation from given class. */
+    public static Collection<MethodDescriptor> collectFrom(Class<? extends Snippet> clazz) {
+        List<MethodDescriptor> descriptors = new ArrayList<MethodDescriptor>();
+        for (Method method : clazz.getMethods()) {
+            if (method.isAnnotationPresent(Rpc.class)) {
+                descriptors.add(new MethodDescriptor(clazz, method));
+            }
+        }
+        return descriptors;
+    }
 
-  /**
-   * Converts a parameter from JSON into a Java Object.
-   *
-   * @return TODO
-   */
-  // TODO(damonkohler): This signature is a bit weird (auto-refactored). The obvious alternative
-  // would be to work on one supplied parameter and return the converted parameter. However, that's
-  // problematic because you lose the ability to call the getXXX methods on the JSON array.
-  //@VisibleForTesting
-  static Object convertParameter(final JSONArray parameters, int index, Type type)
-      throws JSONException, RpcError {
-    try {
-      // We must handle null and numbers explicitly because we cannot magically cast them. We
-      // also need to convert implicitly from numbers to bools.
-      if (parameters.isNull(index)) {
-        return null;
-      } else if (type == Boolean.class) {
+    /**
+     * Invokes the call that belongs to this object with the given parameters. Wraps the response
+     * (possibly an exception) in a JSONObject.
+     *
+     * @param parameters {@code JSONArray} containing the parameters
+     * @return result
+     * @throws Throwable
+     */
+    public Object invoke(SnippetManager manager, final JSONArray parameters) throws Throwable {
+        final Type[] parameterTypes = getGenericParameterTypes();
+        final Object[] args = new Object[parameterTypes.length];
+
+        if (parameters.length() > args.length) {
+            throw new RpcError("Too many parameters specified.");
+        }
+
+        for (int i = 0; i < args.length; i++) {
+            final Type parameterType = parameterTypes[i];
+            if (i < parameters.length()) {
+                args[i] = convertParameter(parameters, i, parameterType);
+            } else {
+                throw new RpcError("Argument " + (i + 1) + " is not present");
+            }
+        }
+
+        return manager.invoke(mClass, mMethod, args);
+    }
+
+    /**
+     * Converts a parameter from JSON into a Java Object.
+     *
+     * @return TODO
+     */
+    // TODO(damonkohler): This signature is a bit weird (auto-refactored). The obvious alternative
+    // would be to work on one supplied parameter and return the converted parameter. However, that's
+    // problematic because you lose the ability to call the getXXX methods on the JSON array.
+    //@VisibleForTesting
+    static Object convertParameter(final JSONArray parameters, int index, Type type)
+            throws JSONException, RpcError {
         try {
-          return parameters.getBoolean(index);
-        } catch (JSONException e) {
-          return new Boolean(parameters.getInt(index) != 0);
+            // We must handle null and numbers explicitly because we cannot magically cast them. We
+            // also need to convert implicitly from numbers to bools.
+            if (parameters.isNull(index)) {
+                return null;
+            } else if (type == Boolean.class) {
+                try {
+                    return parameters.getBoolean(index);
+                } catch (JSONException e) {
+                    return new Boolean(parameters.getInt(index) != 0);
+                }
+            } else if (type == Long.class) {
+                return parameters.getLong(index);
+            } else if (type == Double.class) {
+                return parameters.getDouble(index);
+            } else if (type == Integer.class) {
+                return parameters.getInt(index);
+            } else if (type == Intent.class) {
+                return buildIntent(parameters.getJSONObject(index));
+            } else if (type == Integer[].class) {
+                JSONArray list = parameters.getJSONArray(index);
+                Integer[] result = new Integer[list.length()];
+                for (int i = 0; i < list.length(); i++) {
+                    result[i] = list.getInt(i);
+                }
+                return result;
+            } else if (type == byte[].class) {
+                JSONArray list = parameters.getJSONArray(index);
+                byte[] result = new byte[list.length()];
+                for (int i = 0; i < list.length(); i++) {
+                    result[i] = (byte) list.getInt(i);
+                }
+                return result;
+            } else if (type == String[].class) {
+                JSONArray list = parameters.getJSONArray(index);
+                String[] result = new String[list.length()];
+                for (int i = 0; i < list.length(); i++) {
+                    result[i] = list.getString(i);
+                }
+                return result;
+            } else if (type == JSONObject.class) {
+                return parameters.getJSONObject(index);
+            } else {
+                // Magically cast the parameter to the right Java type.
+                return ((Class<?>) type).cast(parameters.get(index));
+            }
+        } catch (ClassCastException e) {
+            throw new RpcError(
+                    "Argument "
+                            + (index + 1)
+                            + " should be of type "
+                            + ((Class<?>) type).getSimpleName()
+                            + ".");
         }
-      } else if (type == Long.class) {
-        return parameters.getLong(index);
-      } else if (type == Double.class) {
-        return parameters.getDouble(index);
-      } else if (type == Integer.class) {
-        return parameters.getInt(index);
-      } else if (type == Intent.class) {
-        return buildIntent(parameters.getJSONObject(index));
-      } else if (type == Integer[].class) {
-        JSONArray list = parameters.getJSONArray(index);
-        Integer[] result = new Integer[list.length()];
-        for (int i = 0; i < list.length(); i++) {
-          result[i] = list.getInt(i);
+    }
+
+    public static Object buildIntent(JSONObject jsonObject) throws JSONException {
+        Intent intent = new Intent();
+        if (jsonObject.has("action")) {
+            intent.setAction(jsonObject.getString("action"));
         }
-        return result;
-      } else if (type == byte[].class) {
-        JSONArray list = parameters.getJSONArray(index);
-        byte[] result = new byte[list.length()];
-        for (int i = 0; i < list.length(); i++) {
-          result[i] = (byte)list.getInt(i);
+        if (jsonObject.has("data") && jsonObject.has("type")) {
+            intent.setDataAndType(
+                    Uri.parse(jsonObject.optString("data", null)),
+                    jsonObject.optString("type", null));
+        } else if (jsonObject.has("data")) {
+            intent.setData(Uri.parse(jsonObject.optString("data", null)));
+        } else if (jsonObject.has("type")) {
+            intent.setType(jsonObject.optString("type", null));
         }
-        return result;
-      } else if (type == String[].class) {
-        JSONArray list = parameters.getJSONArray(index);
-        String[] result = new String[list.length()];
-        for (int i = 0; i < list.length(); i++) {
-          result[i] = list.getString(i);
+        if (jsonObject.has("packagename") && jsonObject.has("classname")) {
+            intent.setClassName(
+                    jsonObject.getString("packagename"), jsonObject.getString("classname"));
         }
-        return result;
-      } else if (type == JSONObject.class) {
-          return parameters.getJSONObject(index);
-      } else {
-        // Magically cast the parameter to the right Java type.
-        return ((Class<?>) type).cast(parameters.get(index));
-      }
-    } catch (ClassCastException e) {
-      throw new RpcError("Argument " + (index + 1) + " should be of type "
-          + ((Class<?>) type).getSimpleName() + ".");
+        if (jsonObject.has("flags")) {
+            intent.setFlags(jsonObject.getInt("flags"));
+        }
+        if (!jsonObject.isNull("extras")) {
+            AndroidUtil.putExtrasFromJsonObject(jsonObject.getJSONObject("extras"), intent);
+        }
+        if (!jsonObject.isNull("categories")) {
+            JSONArray categories = jsonObject.getJSONArray("categories");
+            for (int i = 0; i < categories.length(); i++) {
+                intent.addCategory(categories.getString(i));
+            }
+        }
+        return intent;
     }
-  }
 
-  public static Object buildIntent(JSONObject jsonObject) throws JSONException {
-    Intent intent = new Intent();
-    if (jsonObject.has("action")) {
-      intent.setAction(jsonObject.getString("action"));
+    public String getName() {
+        return mMethod.getName();
     }
-    if (jsonObject.has("data") && jsonObject.has("type")) {
-      intent.setDataAndType(Uri.parse(jsonObject.optString("data", null)),
-          jsonObject.optString("type", null));
-    } else if (jsonObject.has("data")) {
-      intent.setData(Uri.parse(jsonObject.optString("data", null)));
-    } else if (jsonObject.has("type")) {
-      intent.setType(jsonObject.optString("type", null));
-    }
-    if (jsonObject.has("packagename") && jsonObject.has("classname")) {
-      intent.setClassName(jsonObject.getString("packagename"), jsonObject.getString("classname"));
-    }
-    if (jsonObject.has("flags")) {
-      intent.setFlags(jsonObject.getInt("flags"));
-    }
-    if (!jsonObject.isNull("extras")) {
-      AndroidUtil.putExtrasFromJsonObject(jsonObject.getJSONObject("extras"), intent);
-    }
-    if (!jsonObject.isNull("categories")) {
-      JSONArray categories = jsonObject.getJSONArray("categories");
-      for (int i = 0; i < categories.length(); i++) {
-        intent.addCategory(categories.getString(i));
-      }
-    }
-    return intent;
-  }
 
-  public String getName() {
-    return mMethod.getName();
-  }
-
-  public Type[] getGenericParameterTypes() {
-    return mMethod.getGenericParameterTypes();
-  }
-
-  /**
-   * Returns a human-readable help text for this RPC, based on annotations in the source code.
-   *
-   * @return derived help string
-   */
-  public String getHelp() {
-    StringBuilder paramBuilder = new StringBuilder();
-    Class<?>[] parameterTypes = mMethod.getParameterTypes();
-    for (int i = 0; i < parameterTypes.length; i++) {
-      if (i != 0) {
-        paramBuilder.append(", ");
-      }
-      paramBuilder.append(parameterTypes[i].getSimpleName());
+    public Type[] getGenericParameterTypes() {
+        return mMethod.getGenericParameterTypes();
     }
-    Rpc rpcAnnotation = mMethod.getAnnotation(Rpc.class);
-    String help = String.format(
-            "%s(%s) returns %s  // %s",
-            mMethod.getName(),
-            paramBuilder,
-            //mMethod.getDeclaringClass().getName(),
-            mMethod.getReturnType().getSimpleName(),
-            rpcAnnotation.description());
-    return help;
-  }
+
+    /**
+     * Returns a human-readable help text for this RPC, based on annotations in the source code.
+     *
+     * @return derived help string
+     */
+    public String getHelp() {
+        StringBuilder paramBuilder = new StringBuilder();
+        Class<?>[] parameterTypes = mMethod.getParameterTypes();
+        for (int i = 0; i < parameterTypes.length; i++) {
+            if (i != 0) {
+                paramBuilder.append(", ");
+            }
+            paramBuilder.append(parameterTypes[i].getSimpleName());
+        }
+        Rpc rpcAnnotation = mMethod.getAnnotation(Rpc.class);
+        String help =
+                String.format(
+                        "%s(%s) returns %s  // %s",
+                        mMethod.getName(),
+                        paramBuilder,
+                        mMethod.getReturnType().getSimpleName(),
+                        rpcAnnotation.description());
+        return help;
+    }
 }
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/Rpc.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/Rpc.java
index fa32e9f..af321ba 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/Rpc.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/Rpc.java
@@ -31,8 +31,6 @@
 @Target(ElementType.METHOD)
 @Documented
 public @interface Rpc {
-  /**
-   * Returns brief description of the function. Should be limited to one or two sentences.
-   */
-  String description();
+    /** Returns brief description of the function. Should be limited to one or two sentences. */
+    String description();
 }
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcError.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcError.java
index 0e49b87..0862673 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcError.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcError.java
@@ -19,8 +19,7 @@
 @SuppressWarnings("serial")
 public class RpcError extends Exception {
 
-  public RpcError(String message) {
-    super(message);
-  }
-
+    public RpcError(String message) {
+        super(message);
+    }
 }
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcMinSdk.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcMinSdk.java
index d58a226..f03fd2a 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcMinSdk.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcMinSdk.java
@@ -20,13 +20,10 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
-/**
- * Use this annotation to specify minimum SDK level (if higher than 3).
- *
- */
+/** Use this annotation to specify minimum SDK level (if higher than 3). */
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
 public @interface RpcMinSdk {
-  /** Minimum SDK Level. */
-  int value();
+    /** Minimum SDK Level. */
+    int value();
 }
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/SimpleServer.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/SimpleServer.java
index 617140b..5b59129 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/SimpleServer.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/SimpleServer.java
@@ -17,18 +17,12 @@
 package com.google.android.mobly.snippet.rpc;
 
 import com.google.android.mobly.snippet.util.Log;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.PrintWriter;
-import java.net.BindException;
 import java.net.Inet4Address;
 import java.net.InetAddress;
-import java.net.InetSocketAddress;
 import java.net.NetworkInterface;
 import java.net.ServerSocket;
 import java.net.Socket;
@@ -39,271 +33,278 @@
 import java.util.Enumeration;
 import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
+import org.json.JSONException;
+import org.json.JSONObject;
 
-/**
- * A simple server.
- */
+/** A simple server. */
 public abstract class SimpleServer {
-  private static int threadIndex = 0;
-  private final ConcurrentHashMap<Integer, ConnectionThread> mConnectionThreads =
-      new ConcurrentHashMap<Integer, ConnectionThread>();
-  private final List<SimpleServerObserver> mObservers = new ArrayList<>();
-  private volatile boolean mStopServer = false;
-  private ServerSocket mServer;
-  private Thread mServerThread;
+    private static int threadIndex = 0;
+    private final ConcurrentHashMap<Integer, ConnectionThread> mConnectionThreads =
+            new ConcurrentHashMap<Integer, ConnectionThread>();
+    private final List<SimpleServerObserver> mObservers = new ArrayList<>();
+    private volatile boolean mStopServer = false;
+    private ServerSocket mServer;
+    private Thread mServerThread;
 
-  public interface SimpleServerObserver {
-    void onConnect();
-    void onDisconnect();
-  }
+    public interface SimpleServerObserver {
+        void onConnect();
 
-  protected abstract void handleConnection(Socket socket) throws Exception;
-  protected abstract void handleRPCConnection(Socket socket,
-                                              Integer UID,
-                                              BufferedReader reader,
-                                              PrintWriter writer) throws Exception;
-
-  /** Adds an observer. */
-  public void addObserver(SimpleServerObserver observer) {
-    mObservers.add(observer);
-  }
-
-  /** Removes an observer. */
-  public void removeObserver(SimpleServerObserver observer) {
-    mObservers.remove(observer);
-  }
-
-  private void notifyOnConnect() {
-    for (SimpleServerObserver observer : mObservers) {
-      observer.onConnect();
-    }
-  }
-
-  private void notifyOnDisconnect() {
-    for (SimpleServerObserver observer : mObservers) {
-      observer.onDisconnect();
-    }
-  }
-
-  private final class ConnectionThread extends Thread {
-    private final Socket mmSocket;
-    private final BufferedReader reader;
-    private final PrintWriter writer;
-    private final Integer UID;
-    private final boolean isRpc;
-
-    private ConnectionThread(Socket socket, boolean rpc, Integer uid, BufferedReader reader, PrintWriter writer) {
-      setName("SimpleServer ConnectionThread " + getId());
-      mmSocket = socket;
-      this.UID = uid;
-      this.reader = reader;
-      this.writer = writer;
-      this.isRpc = rpc;
+        void onDisconnect();
     }
 
-    @Override
-    public void run() {
-      Log.v("Server thread " + getId() + " started.");
-      try {
-        if(isRpc) {
-          Log.d("Handling RPC connection in "+getId());
-          handleRPCConnection(mmSocket, UID, reader, writer);
-        }else{
-          Log.d("Handling Non-RPC connection in "+getId());
-          handleConnection(mmSocket);
+    protected abstract void handleConnection(Socket socket) throws Exception;
+
+    protected abstract void handleRPCConnection(
+            Socket socket, Integer UID, BufferedReader reader, PrintWriter writer) throws Exception;
+
+    /** Adds an observer. */
+    public void addObserver(SimpleServerObserver observer) {
+        mObservers.add(observer);
+    }
+
+    /** Removes an observer. */
+    public void removeObserver(SimpleServerObserver observer) {
+        mObservers.remove(observer);
+    }
+
+    private void notifyOnConnect() {
+        for (SimpleServerObserver observer : mObservers) {
+            observer.onConnect();
         }
-      } catch (Exception e) {
-        if (!mStopServer) {
-          Log.e("Server error.", e);
+    }
+
+    private void notifyOnDisconnect() {
+        for (SimpleServerObserver observer : mObservers) {
+            observer.onDisconnect();
         }
-      } finally {
-        close();
-        mConnectionThreads.remove(this.UID);
-        notifyOnDisconnect();
-        Log.v("Server thread " + getId() + " stopped.");
-      }
     }
 
-    private void close() {
-      if (mmSocket != null) {
-        try {
-          mmSocket.close();
-        } catch (IOException e) {
-          Log.e(e.getMessage(), e);
+    private final class ConnectionThread extends Thread {
+        private final Socket mmSocket;
+        private final BufferedReader reader;
+        private final PrintWriter writer;
+        private final Integer UID;
+        private final boolean isRpc;
+
+        private ConnectionThread(
+                Socket socket,
+                boolean rpc,
+                Integer uid,
+                BufferedReader reader,
+                PrintWriter writer) {
+            setName("SimpleServer ConnectionThread " + getId());
+            mmSocket = socket;
+            this.UID = uid;
+            this.reader = reader;
+            this.writer = writer;
+            this.isRpc = rpc;
         }
-      }
-    }
-  }
 
-  /** Returns the number of active connections to this server. */
-  public int getNumberOfConnections() {
-    return mConnectionThreads.size();
-  }
-
-  public static InetAddress getPrivateInetAddress() throws UnknownHostException, SocketException {
-
-    InetAddress candidate = null;
-    Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
-    for (NetworkInterface netint : Collections.list(nets)) {
-      if (!netint.isLoopback() || !netint.isUp()) { // Ignore if localhost or not active
-        continue;
-      }
-      Enumeration<InetAddress> addresses = netint.getInetAddresses();
-      for (InetAddress address : Collections.list(addresses)) {
-        if (address instanceof Inet4Address) {
-          Log.d("local address " + address);
-          return address; // Prefer ipv4
+        @Override
+        public void run() {
+            Log.v("Server thread " + getId() + " started.");
+            try {
+                if (isRpc) {
+                    Log.d("Handling RPC connection in " + getId());
+                    handleRPCConnection(mmSocket, UID, reader, writer);
+                } else {
+                    Log.d("Handling Non-RPC connection in " + getId());
+                    handleConnection(mmSocket);
+                }
+            } catch (Exception e) {
+                if (!mStopServer) {
+                    Log.e("Server error.", e);
+                }
+            } finally {
+                close();
+                mConnectionThreads.remove(this.UID);
+                notifyOnDisconnect();
+                Log.v("Server thread " + getId() + " stopped.");
+            }
         }
-        candidate = address; // Probably an ipv6
-      }
-    }
-    if (candidate != null) {
-      return candidate; // return ipv6 address if no suitable ipv6
-    }
-    return InetAddress.getLocalHost(); // No damn matches. Give up, return local host.
-  }
 
-  public static InetAddress getPublicInetAddress() throws UnknownHostException, SocketException {
-
-    InetAddress candidate = null;
-    Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
-    for (NetworkInterface netint : Collections.list(nets)) {
-      if (netint.isLoopback() || !netint.isUp()) { // Ignore if localhost or not active
-        continue;
-      }
-      Enumeration<InetAddress> addresses = netint.getInetAddresses();
-      for (InetAddress address : Collections.list(addresses)) {
-        if (address instanceof Inet4Address) {
-          return address; // Prefer ipv4
+        private void close() {
+            if (mmSocket != null) {
+                try {
+                    mmSocket.close();
+                } catch (IOException e) {
+                    Log.e(e.getMessage(), e);
+                }
+            }
         }
-        candidate = address; // Probably an ipv6
-      }
     }
-    if (candidate != null) {
-      return candidate; // return ipv6 address if no suitable ipv6
+
+    /** Returns the number of active connections to this server. */
+    public int getNumberOfConnections() {
+        return mConnectionThreads.size();
     }
-    return InetAddress.getLocalHost(); // No damn matches. Give up, return local host.
-  }
 
-  /**
-   * Starts the RPC server bound to the localhost address.
-   *
-   * @param port
-   *          the port to bind to or 0 to pick any unused port
-   *
-   * @throws IOException
-   */
-  public void startLocal(int port) throws IOException {
-    InetAddress address;
-    // address = InetAddress.getLocalHost();
-    address = getPrivateInetAddress();
-    mServer = new ServerSocket(port, 5, address);
-    start();
-  }
+    public static InetAddress getPrivateInetAddress() throws UnknownHostException, SocketException {
 
-  private void start() {
-    mServerThread = new Thread() {
-      @Override
-      public void run() {
-        while (!mStopServer) {
-          try {
-            Socket sock = mServer.accept();
-            if (!mStopServer) {
-              startConnectionThread(sock);
+        InetAddress candidate = null;
+        Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
+        for (NetworkInterface netint : Collections.list(nets)) {
+            if (!netint.isLoopback() || !netint.isUp()) { // Ignore if localhost or not active
+                continue;
+            }
+            Enumeration<InetAddress> addresses = netint.getInetAddresses();
+            for (InetAddress address : Collections.list(addresses)) {
+                if (address instanceof Inet4Address) {
+                    Log.d("local address " + address);
+                    return address; // Prefer ipv4
+                }
+                candidate = address; // Probably an ipv6
+            }
+        }
+        if (candidate != null) {
+            return candidate; // return ipv6 address if no suitable ipv6
+        }
+        return InetAddress.getLocalHost(); // No damn matches. Give up, return local host.
+    }
+
+    public static InetAddress getPublicInetAddress() throws UnknownHostException, SocketException {
+
+        InetAddress candidate = null;
+        Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
+        for (NetworkInterface netint : Collections.list(nets)) {
+            if (netint.isLoopback() || !netint.isUp()) { // Ignore if localhost or not active
+                continue;
+            }
+            Enumeration<InetAddress> addresses = netint.getInetAddresses();
+            for (InetAddress address : Collections.list(addresses)) {
+                if (address instanceof Inet4Address) {
+                    return address; // Prefer ipv4
+                }
+                candidate = address; // Probably an ipv6
+            }
+        }
+        if (candidate != null) {
+            return candidate; // return ipv6 address if no suitable ipv6
+        }
+        return InetAddress.getLocalHost(); // No damn matches. Give up, return local host.
+    }
+
+    /**
+     * Starts the RPC server bound to the localhost address.
+     *
+     * @param port the port to bind to or 0 to pick any unused port
+     * @throws IOException
+     */
+    public void startLocal(int port) throws IOException {
+        InetAddress address;
+        // address = InetAddress.getLocalHost();
+        address = getPrivateInetAddress();
+        mServer = new ServerSocket(port, 5, address);
+        start();
+    }
+
+    private void start() {
+        mServerThread =
+                new Thread() {
+                    @Override
+                    public void run() {
+                        while (!mStopServer) {
+                            try {
+                                Socket sock = mServer.accept();
+                                if (!mStopServer) {
+                                    startConnectionThread(sock);
+                                } else {
+                                    sock.close();
+                                }
+                            } catch (IOException e) {
+                                if (!mStopServer) {
+                                    Log.e("Failed to accept connection.", e);
+                                }
+                            } catch (JSONException e) {
+                                if (!mStopServer) {
+                                    Log.e("Failed to parse request.", e);
+                                }
+                            }
+                        }
+                    }
+                };
+        mServerThread.start();
+        Log.v("Bound to " + mServer.getInetAddress());
+    }
+
+    private void startConnectionThread(final Socket sock) throws IOException, JSONException {
+        BufferedReader reader =
+                new BufferedReader(new InputStreamReader(sock.getInputStream()), 8192);
+        PrintWriter writer = new PrintWriter(sock.getOutputStream(), true);
+        String data;
+        if ((data = reader.readLine()) != null) {
+            Log.v("Received: " + data);
+            JSONObject request = new JSONObject(data);
+            if (request.has("cmd") && request.has("uid")) {
+                String cmd = request.getString("cmd");
+                int uid = request.getInt("uid");
+                JSONObject result = new JSONObject();
+                if (cmd.equals("initiate")) {
+                    Log.d("Initiate a new session");
+                    threadIndex += 1;
+                    int mUID = threadIndex;
+                    ConnectionThread networkThread =
+                            new ConnectionThread(sock, true, mUID, reader, writer);
+                    mConnectionThreads.put(mUID, networkThread);
+                    networkThread.start();
+                    notifyOnConnect();
+                    result.put("uid", mUID);
+                    result.put("status", true);
+                    result.put("error", null);
+                } else if (cmd.equals("continue")) {
+                    Log.d("Continue an existing session");
+                    Log.d("keys: " + mConnectionThreads.keySet().toString());
+                    if (!mConnectionThreads.containsKey(uid)) {
+                        result.put("uid", uid);
+                        result.put("status", false);
+                        result.put("error", "Session does not exist.");
+                    } else {
+                        ConnectionThread networkThread =
+                                new ConnectionThread(sock, true, uid, reader, writer);
+                        mConnectionThreads.put(uid, networkThread);
+                        networkThread.start();
+                        notifyOnConnect();
+                        result.put("uid", uid);
+                        result.put("status", true);
+                        result.put("error", null);
+                    }
+                } else {
+                    result.put("uid", uid);
+                    result.put("status", false);
+                    result.put("error", "Unrecognized command.");
+                }
+                writer.write(result + "\n");
+                writer.flush();
+                Log.v("Sent: " + result);
             } else {
-              sock.close();
+                ConnectionThread networkThread =
+                        new ConnectionThread(sock, false, 0, reader, writer);
+                mConnectionThreads.put(0, networkThread);
+                networkThread.start();
+                notifyOnConnect();
             }
-          } catch (IOException e) {
-            if (!mStopServer) {
-              Log.e("Failed to accept connection.", e);
-            }
-          } catch (JSONException e) {
-            if (!mStopServer) {
-              Log.e("Failed to parse request.", e);
-            }
-          }
         }
-      }
-    };
-    mServerThread.start();
-    Log.v("Bound to " + mServer.getInetAddress());
-  }
+    }
 
-  private void startConnectionThread(final Socket sock) throws IOException, JSONException {
-    BufferedReader reader =
-        new BufferedReader(new InputStreamReader(sock.getInputStream()), 8192);
-    PrintWriter writer = new PrintWriter(sock.getOutputStream(), true);
-    String data;
-    if((data = reader.readLine()) != null) {
-      Log.v("Received: " + data);
-      JSONObject request = new JSONObject(data);
-      if(request.has("cmd") && request.has("uid")) {
-        String cmd = request.getString("cmd");
-        int uid = request.getInt("uid");
-        JSONObject result = new JSONObject();
-        if(cmd.equals("initiate")) {
-          Log.d("Initiate a new session");
-          threadIndex += 1;
-          int mUID = threadIndex;
-          ConnectionThread networkThread = new ConnectionThread(sock,true,mUID,reader,writer);
-          mConnectionThreads.put(mUID, networkThread);
-          networkThread.start();
-          notifyOnConnect();
-          result.put("uid", mUID);
-          result.put("status",true);
-          result.put("error", null);
-        }else if(cmd.equals("continue")) {
-          Log.d("Continue an existing session");
-          Log.d("keys: "+mConnectionThreads.keySet().toString());
-          if(!mConnectionThreads.containsKey(uid)) {
-            result.put("uid", uid);
-            result.put("status",false);
-            result.put("error", "Session does not exist.");
-          }else{
-            ConnectionThread networkThread = new ConnectionThread(sock,true,uid,reader,writer);
-            mConnectionThreads.put(uid, networkThread);
-            networkThread.start();
-            notifyOnConnect();
-            result.put("uid", uid);
-            result.put("status",true);
-            result.put("error", null);
-          }
-        }else {
-          result.put("uid", uid);
-          result.put("status",false);
-          result.put("error", "Unrecognized command.");
+    public void shutdown() {
+        // Stop listening on the server socket to ensure that
+        // beyond this point there are no incoming requests.
+        mStopServer = true;
+        try {
+            mServer.close();
+        } catch (IOException e) {
+            Log.e("Failed to close server socket.", e);
         }
-        writer.write(result + "\n");
-        writer.flush();
-        Log.v("Sent: " + result);
-      }else{
-        ConnectionThread networkThread = new ConnectionThread(sock,false,0,reader,writer);
-        mConnectionThreads.put(0, networkThread);
-        networkThread.start();
-        notifyOnConnect();
-      }
+        // Since the server is not running, the mNetworkThreads set can only
+        // shrink from this point onward. We can just stop all of the running helper
+        // threads. In the worst case, one of the running threads will already have
+        // shut down. Since this is a CopyOnWriteList, we don't have to worry about
+        // concurrency issues while iterating over the set of threads.
+        for (ConnectionThread connectionThread : mConnectionThreads.values()) {
+            connectionThread.close();
+        }
+        for (SimpleServerObserver observer : mObservers) {
+            removeObserver(observer);
+        }
     }
-  }
-
-  public void shutdown() {
-    // Stop listening on the server socket to ensure that
-    // beyond this point there are no incoming requests.
-    mStopServer = true;
-    try {
-      mServer.close();
-    } catch (IOException e) {
-      Log.e("Failed to close server socket.", e);
-    }
-    // Since the server is not running, the mNetworkThreads set can only
-    // shrink from this point onward. We can just stop all of the running helper
-    // threads. In the worst case, one of the running threads will already have
-    // shut down. Since this is a CopyOnWriteList, we don't have to worry about
-    // concurrency issues while iterating over the set of threads.
-    for (ConnectionThread connectionThread : mConnectionThreads.values()) {
-      connectionThread.close();
-    }
-    for (SimpleServerObserver observer : mObservers) {
-      removeObserver(observer);
-    }
-  }
 }
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/AndroidUtil.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/AndroidUtil.java
index 5f96647..46c4940 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/AndroidUtil.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/AndroidUtil.java
@@ -18,7 +18,6 @@
 
 import android.content.Intent;
 import android.os.Bundle;
-
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
@@ -28,8 +27,8 @@
 
     // TODO(damonkohler): Pull this out into proper argument deserialization and support
     // complex/nested types being passed in.
-    public static void putExtrasFromJsonObject(JSONObject extras,
-                                               Intent intent) throws JSONException {
+    public static void putExtrasFromJsonObject(JSONObject extras, Intent intent)
+            throws JSONException {
         JSONArray names = extras.names();
         for (int i = 0; i < names.length(); i++) {
             String name = names.getString(i);
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/Log.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/Log.java
index bb1ce10..70c93ba 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/Log.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/Log.java
@@ -25,158 +25,162 @@
 import android.widget.Toast;
 
 public class Log {
-  private Log() {
-    // Utility class.
-  }
+    private Log() {
+        // Utility class.
+    }
 
-  private static String getTag() {
-    StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
-    String fullClassName = stackTraceElements[4].getClassName();
-    String className = fullClassName.substring(fullClassName.lastIndexOf(".") + 1);
-    int lineNumber = stackTraceElements[4].getLineNumber();
-    return "sl4a." + className + ":" + lineNumber;
-  }
+    private static String getTag() {
+        StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
+        String fullClassName = stackTraceElements[4].getClassName();
+        String className = fullClassName.substring(fullClassName.lastIndexOf(".") + 1);
+        int lineNumber = stackTraceElements[4].getLineNumber();
+        return "sl4a." + className + ":" + lineNumber;
+    }
 
-  private static void toast(Context context, String message) {
-    Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
-  }
+    private static void toast(Context context, String message) {
+        Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
+    }
 
-  public static void notify(Context context, String title, String contentTitle, String message) {
-    android.util.Log.v(getTag(), String.format("%s %s", contentTitle, message));
+    public static void notify(Context context, String title, String contentTitle, String message) {
+        android.util.Log.v(getTag(), String.format("%s %s", contentTitle, message));
 
-    String packageName = context.getPackageName();
-    int iconId = context.getResources().getIdentifier("stat_sys_warning", "drawable", packageName);
-    NotificationManager notificationManager =
-        (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-    Notification.Builder builder = new Notification.Builder(context);
-    builder.setSmallIcon(iconId > 0 ? iconId : -1)
-           .setTicker(title)
-           .setWhen(0)
-           .setContentTitle(contentTitle)
-           .setContentText(message)
-           .setContentIntent(PendingIntent.getService(context, 0, null, 0));
-    Notification note = builder.getNotification();
-    note.contentView.getLayoutId();
-    notificationManager.notify(NotificationIdFactory.create(), note);
-  }
+        String packageName = context.getPackageName();
+        int iconId =
+                context.getResources().getIdentifier("stat_sys_warning", "drawable", packageName);
+        NotificationManager notificationManager =
+                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+        Notification.Builder builder = new Notification.Builder(context);
+        builder.setSmallIcon(iconId > 0 ? iconId : -1)
+                .setTicker(title)
+                .setWhen(0)
+                .setContentTitle(contentTitle)
+                .setContentText(message)
+                .setContentIntent(PendingIntent.getService(context, 0, null, 0));
+        Notification note = builder.getNotification();
+        note.contentView.getLayoutId();
+        notificationManager.notify(NotificationIdFactory.create(), note);
+    }
 
-  public static void showDialog(final Context context, final String title, final String message) {
-    android.util.Log.v(getTag(), String.format("%s %s", title, message));
+    public static void showDialog(final Context context, final String title, final String message) {
+        android.util.Log.v(getTag(), String.format("%s %s", title, message));
 
-    MainThread.run(context, new Runnable() {
-      @Override
-      public void run() {
-        AlertDialog.Builder builder = new AlertDialog.Builder(context);
-        builder.setTitle(title);
-        builder.setMessage(message);
+        MainThread.run(
+                context,
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        AlertDialog.Builder builder = new AlertDialog.Builder(context);
+                        builder.setTitle(title);
+                        builder.setMessage(message);
 
-        DialogInterface.OnClickListener buttonListener = new DialogInterface.OnClickListener() {
-          @Override
-          public void onClick(DialogInterface dialog, int which) {
-            dialog.dismiss();
-          }
-        };
-        builder.setPositiveButton("Ok", buttonListener);
-        builder.show();
-      }
-    });
-  }
+                        DialogInterface.OnClickListener buttonListener =
+                                new DialogInterface.OnClickListener() {
+                                    @Override
+                                    public void onClick(DialogInterface dialog, int which) {
+                                        dialog.dismiss();
+                                    }
+                                };
+                        builder.setPositiveButton("Ok", buttonListener);
+                        builder.show();
+                    }
+                });
+    }
 
-  public static void v(String message) {
-    android.util.Log.v(getTag(), message);
-  }
+    public static void v(String message) {
+        android.util.Log.v(getTag(), message);
+    }
 
-  public static void v(String message, Throwable e) {
-    android.util.Log.v(getTag(), message, e);
-  }
+    public static void v(String message, Throwable e) {
+        android.util.Log.v(getTag(), message, e);
+    }
 
-  public static void v(Context context, String message) {
-    toast(context, message);
-    android.util.Log.v(getTag(), message);
-  }
+    public static void v(Context context, String message) {
+        toast(context, message);
+        android.util.Log.v(getTag(), message);
+    }
 
-  public static void v(Context context, String message, Throwable e) {
-    toast(context, message);
-    android.util.Log.v(getTag(), message, e);
-  }
+    public static void v(Context context, String message, Throwable e) {
+        toast(context, message);
+        android.util.Log.v(getTag(), message, e);
+    }
 
-  public static void e(Throwable e) {
-    android.util.Log.e(getTag(), "Error", e);
-  }
+    public static void e(Throwable e) {
+        android.util.Log.e(getTag(), "Error", e);
+    }
 
-  public static void e(String message) {
-    android.util.Log.e(getTag(), message);
-  }
+    public static void e(String message) {
+        android.util.Log.e(getTag(), message);
+    }
 
-  public static void e(String message, Throwable e) {
-    android.util.Log.e(getTag(), message, e);
-  }
+    public static void e(String message, Throwable e) {
+        android.util.Log.e(getTag(), message, e);
+    }
 
-  public static void e(Context context, String message) {
-    toast(context, message);
-    android.util.Log.e(getTag(), message);
-  }
+    public static void e(Context context, String message) {
+        toast(context, message);
+        android.util.Log.e(getTag(), message);
+    }
 
-  public static void e(Context context, String message, Throwable e) {
-    toast(context, message);
-    android.util.Log.e(getTag(), message, e);
-  }
+    public static void e(Context context, String message, Throwable e) {
+        toast(context, message);
+        android.util.Log.e(getTag(), message, e);
+    }
 
-  public static void w(Throwable e) {
-    android.util.Log.w(getTag(), "Warning", e);
-  }
+    public static void w(Throwable e) {
+        android.util.Log.w(getTag(), "Warning", e);
+    }
 
-  public static void w(String message) {
-    android.util.Log.w(getTag(), message);
-  }
+    public static void w(String message) {
+        android.util.Log.w(getTag(), message);
+    }
 
-  public static void w(String message, Throwable e) {
-    android.util.Log.w(getTag(), message, e);
-  }
+    public static void w(String message, Throwable e) {
+        android.util.Log.w(getTag(), message, e);
+    }
 
-  public static void w(Context context, String message) {
-    toast(context, message);
-    android.util.Log.w(getTag(), message);
-  }
+    public static void w(Context context, String message) {
+        toast(context, message);
+        android.util.Log.w(getTag(), message);
+    }
 
-  public static void w(Context context, String message, Throwable e) {
-    toast(context, message);
-    android.util.Log.w(getTag(), message, e);
-  }
+    public static void w(Context context, String message, Throwable e) {
+        toast(context, message);
+        android.util.Log.w(getTag(), message, e);
+    }
 
-  public static void d(String message) {
-    android.util.Log.d(getTag(), message);
-  }
+    public static void d(String message) {
+        android.util.Log.d(getTag(), message);
+    }
 
-  public static void d(String message, Throwable e) {
-    android.util.Log.d(getTag(), message, e);
-  }
+    public static void d(String message, Throwable e) {
+        android.util.Log.d(getTag(), message, e);
+    }
 
-  public static void d(Context context, String message) {
-    toast(context, message);
-    android.util.Log.d(getTag(), message);
-  }
+    public static void d(Context context, String message) {
+        toast(context, message);
+        android.util.Log.d(getTag(), message);
+    }
 
-  public static void d(Context context, String message, Throwable e) {
-    toast(context, message);
-    android.util.Log.d(getTag(), message, e);
-  }
+    public static void d(Context context, String message, Throwable e) {
+        toast(context, message);
+        android.util.Log.d(getTag(), message, e);
+    }
 
-  public static void i(String message) {
-    android.util.Log.i(getTag(), message);
-  }
+    public static void i(String message) {
+        android.util.Log.i(getTag(), message);
+    }
 
-  public static void i(String message, Throwable e) {
-    android.util.Log.i(getTag(), message, e);
-  }
+    public static void i(String message, Throwable e) {
+        android.util.Log.i(getTag(), message, e);
+    }
 
-  public static void i(Context context, String message) {
-    toast(context, message);
-    android.util.Log.i(getTag(), message);
-  }
+    public static void i(Context context, String message) {
+        toast(context, message);
+        android.util.Log.i(getTag(), message);
+    }
 
-  public static void i(Context context, String message, Throwable e) {
-    toast(context, message);
-    android.util.Log.i(getTag(), message, e);
-  }
+    public static void i(Context context, String message, Throwable e) {
+        toast(context, message);
+        android.util.Log.i(getTag(), message, e);
+    }
 }
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/MainThread.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/MainThread.java
index 0e13e74..480498a 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/MainThread.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/MainThread.java
@@ -18,50 +18,50 @@
 
 import android.content.Context;
 import android.os.Handler;
-
 import com.google.android.mobly.snippet.future.FutureResult;
-
 import java.util.concurrent.Callable;
 
 public class MainThread {
 
-  private MainThread() {
-    // Utility class.
-  }
-
-  /**
-   * Executed in the main thread, returns the result of an execution. Anything that runs here should
-   * finish quickly to avoid hanging the UI thread.
-   */
-  public static <T> T run(Context context, final Callable<T> task) {
-    final FutureResult<T> result = new FutureResult<T>();
-    Handler handler = new Handler(context.getMainLooper());
-    handler.post(new Runnable() {
-      @Override
-      public void run() {
-        try {
-          result.set(task.call());
-        } catch (Exception e) {
-          Log.e(e);
-          result.set(null);
-        }
-      }
-    });
-    try {
-      return result.get();
-    } catch (InterruptedException e) {
-      Log.e(e);
+    private MainThread() {
+        // Utility class.
     }
-    return null;
-  }
 
-  public static void run(Context context, final Runnable task) {
-    Handler handler = new Handler(context.getMainLooper());
-    handler.post(new Runnable() {
-      @Override
-      public void run() {
-        task.run();
-      }
-    });
-  }
+    /**
+     * Executed in the main thread, returns the result of an execution. Anything that runs here
+     * should finish quickly to avoid hanging the UI thread.
+     */
+    public static <T> T run(Context context, final Callable<T> task) {
+        final FutureResult<T> result = new FutureResult<T>();
+        Handler handler = new Handler(context.getMainLooper());
+        handler.post(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            result.set(task.call());
+                        } catch (Exception e) {
+                            Log.e(e);
+                            result.set(null);
+                        }
+                    }
+                });
+        try {
+            return result.get();
+        } catch (InterruptedException e) {
+            Log.e(e);
+        }
+        return null;
+    }
+
+    public static void run(Context context, final Runnable task) {
+        Handler handler = new Handler(context.getMainLooper());
+        handler.post(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        task.run();
+                    }
+                });
+    }
 }
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/NotificationIdFactory.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/NotificationIdFactory.java
index d32977d..39cea5e 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/NotificationIdFactory.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/NotificationIdFactory.java
@@ -21,16 +21,13 @@
 /**
  * Creates unique ids to identify the notifications created by the android scripting service and the
  * trigger service.
- *
- *
  */
 public final class NotificationIdFactory {
-  private static final AtomicInteger mNextId = new AtomicInteger(0);
+    private static final AtomicInteger mNextId = new AtomicInteger(0);
 
-  public static int create() {
-    return mNextId.incrementAndGet();
-  }
+    public static int create() {
+        return mNextId.incrementAndGet();
+    }
 
-  private NotificationIdFactory() {
-  }
+    private NotificationIdFactory() {}
 }
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/SnippetLibException.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/SnippetLibException.java
index 65e543f..e6f5af7 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/SnippetLibException.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/SnippetLibException.java
@@ -19,16 +19,15 @@
 @SuppressWarnings("serial")
 public class SnippetLibException extends Exception {
 
-  public SnippetLibException(Exception e) {
-    super(e);
-  }
+    public SnippetLibException(Exception e) {
+        super(e);
+    }
 
-  public SnippetLibException(String message) {
-    super(message);
-  }
+    public SnippetLibException(String message) {
+        super(message);
+    }
 
-  public SnippetLibException(String message, Exception e) {
-    super(message, e);
-  }
-
+    public SnippetLibException(String message, Exception e) {
+        super(message, e);
+    }
 }