Create a builtin help() RPC.

Cleans up the RPC description handling and allows removal of a lot of unneeded annotations.
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/Constants.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/Constants.java
index 898975d..51b9a88 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/Constants.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/Constants.java
@@ -16,14 +16,8 @@
 
 package com.google.android.mobly.snippet;
 
-import android.content.ComponentName;
-
 public interface Constants {
-    public static final String ACTION_KILL =
-            "com.google.android.mobly.snippet.action.KILL";
-    public static final String ACTION_LAUNCH_SERVER =
-            "com.google.android.mobly.snippet.action.LAUNCH_SERVER";
-
-    public static final String EXTRA_SERVICE_PORT =
-            "com.google.android.mobly.snippet.extra.SERVICE_PORT";
+    String ACTION_KILL = "com.google.android.mobly.snippet.action.KILL";
+    String ACTION_LAUNCH_SERVER = "com.google.android.mobly.snippet.action.LAUNCH_SERVER";
+    String EXTRA_SERVICE_PORT =  "com.google.android.mobly.snippet.extra.SERVICE_PORT";
 }
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/facade/FacadeManager.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/facade/FacadeManager.java
index 7244539..f9116cb 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/facade/FacadeManager.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/facade/FacadeManager.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 
-import com.google.android.mobly.snippet.rpc.RpcDeprecated;
 import com.google.android.mobly.snippet.rpc.RpcMinSdk;
 import com.google.android.mobly.snippet.rpc.Snippet;
 import com.google.android.mobly.snippet.rpc.SnippetManager;
@@ -45,11 +44,7 @@
   public Object invoke(Class<? extends Snippet> clazz, Method method, Object[] args)
       throws Exception {
     try {
-      if (method.isAnnotationPresent(RpcDeprecated.class)) {
-        String replacedBy = method.getAnnotation(RpcDeprecated.class).value();
-        String title = method.getName() + " is deprecated";
-        Log.notify(mContext, title, title, String.format("Please use %s instead.", replacedBy));
-      } else if (method.isAnnotationPresent(RpcMinSdk.class)) {
+      if (method.isAnnotationPresent(RpcMinSdk.class)) {
         int requiredSdkLevel = method.getAnnotation(RpcMinSdk.class).value();
         if (mSdkLevel < requiredSdkLevel) {
           throw new SnippetLibException(
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 1fd832c..fd13b3f 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
@@ -21,41 +21,20 @@
 import com.google.android.mobly.snippet.facade.ReflectionFacadeManagerFactory;
 
 import java.net.InetSocketAddress;
-import java.util.UUID;
 
 public class AndroidProxy {
 
     private InetSocketAddress mAddress;
     private final JsonRpcServer mJsonRpcServer;
-    private final UUID mSecret;
     private final SnippetManagerFactory mFacadeManagerFactory;
 
-    /**
-     *
-     * @param context
-     *          Android context (required to build facades).
-     * @param requiresHandshake
-     *          indicates whether RPC security protocol should be enabled.
-     */
-    public AndroidProxy(Context context, boolean requiresHandshake) {
-        if (requiresHandshake) {
-            mSecret = UUID.randomUUID();
-        } else {
-            mSecret = null;
-        }
+    public AndroidProxy(Context context) {
         mFacadeManagerFactory = new ReflectionFacadeManagerFactory(context);
-        mJsonRpcServer = new JsonRpcServer(mFacadeManagerFactory, getSecret());
+        mJsonRpcServer = new JsonRpcServer(mFacadeManagerFactory);
     }
 
     public InetSocketAddress startLocal(int port) {
         mAddress = mJsonRpcServer.startLocal(port);
         return mAddress;
     }
-
-    private String getSecret() {
-        if (mSecret == null) {
-            return null;
-        }
-        return mSecret.toString();
-    }
 }
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/Converter.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/Converter.java
deleted file mode 100644
index 8de44c1..0000000
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/Converter.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2016 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.google.android.mobly.snippet.rpc;
-
-/**
- * A converter can take a String and turn it into an instance of type T (the type parameter to the
- * converter).
- *
- */
-public interface Converter<T> {
-
-  /** Convert a string into type T. */
-  T convert(String value);
-}
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 9e57619..6834507 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
@@ -24,11 +24,11 @@
 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.
- *
  */
 public class JsonRpcServer extends SimpleServer {
 
@@ -36,16 +36,12 @@
 
     private final SnippetManagerFactory mSnippetManagerFactory;
 
-    // private final String mHandshake;
-
     /**
      * Construct a {@link JsonRpcServer} connected to the provided {@link SnippetManager}.
      *
      * @param managerFactory the {@link SnippetManager} to register with the server
-     * @param handshake the secret handshake required for authorization to use this server
      */
-    public JsonRpcServer(SnippetManagerFactory managerFactory, String handshake) {
-        // mHandshake = handshake;
+    public JsonRpcServer(SnippetManagerFactory managerFactory) {
         mSnippetManagerFactory = managerFactory;
     }
 
@@ -76,7 +72,6 @@
                 receiverManager = mSnippetManagerFactory.create(UID);
             }
         }
-        // boolean passedAuthentication = false;
         String data;
         while ((data = reader.readLine()) != null) {
             Log.v("Session " + UID + " Received: " + data);
@@ -85,6 +80,11 @@
             String method = request.getString("method");
             JSONArray params = request.getJSONArray("params");
 
+            if (method.equals("help")) {
+                help(writer, id, receiverManager, UID);
+                continue;
+            }
+
             MethodDescriptor rpc = receiverManager.getMethodDescriptor(method);
             if (rpc == null) {
                 send(writer, JsonRpcResult.error(id, new RpcError("Unknown RPC: " + method)), UID);
@@ -111,6 +111,16 @@
         }
     }
 
+    private void help(PrintWriter writer, int id, SnippetManager receiverManager, Integer UID)
+        throws JSONException {
+        StringBuilder result = new StringBuilder("Known methods:\n");
+        for (String method : receiverManager.getMethodNames()) {
+            MethodDescriptor descriptor = receiverManager.getMethodDescriptor(method);
+            result.append("  ").append(descriptor.getHelp()).append("\n");
+        }
+        send(writer, JsonRpcResult.result(id, result), UID);
+    }
+
     private void send(PrintWriter writer, JSONObject result, int UID) {
         writer.write(result + "\n");
         writer.flush();
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/JsonSerializable.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/JsonSerializable.java
index bffd13d..5871e01 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/JsonSerializable.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/JsonSerializable.java
@@ -20,5 +20,5 @@
 import org.json.JSONObject;
 
 public interface JsonSerializable {
-    public JSONObject toJSON() throws JSONException;
+    JSONObject toJSON() throws JSONException;
 }
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 d50f070..c110da0 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
@@ -43,8 +43,6 @@
  *
  */
 public final class MethodDescriptor {
-  private static final Map<Class<?>, Converter<?>> sConverters = populateConverters();
-
   private final Method mMethod;
   private final Class<? extends Snippet> mClass;
 
@@ -79,10 +77,8 @@
    * @throws Throwable
    */
   public Object invoke(SnippetManager manager, final JSONArray parameters) throws Throwable {
-
     final Type[] parameterTypes = getGenericParameterTypes();
     final Object[] args = new Object[parameterTypes.length];
-    final Annotation annotations[][] = getParameterAnnotations();
 
     if (parameters.length() > args.length) {
       throw new RpcError("Too many parameters specified.");
@@ -92,8 +88,6 @@
       final Type parameterType = parameterTypes[i];
       if (i < parameters.length()) {
         args[i] = convertParameter(parameters, i, parameterType);
-      } else if (MethodDescriptor.hasDefaultValue(annotations[i])) {
-        args[i] = MethodDescriptor.getDefaultValue(parameterType, annotations[i]);
       } else {
         throw new RpcError("Argument " + (i + 1) + " is not present");
       }
@@ -102,35 +96,8 @@
     return invoke(manager, args);
   }
 
-  /**
-   * Invokes the call that belongs to this object with the given parameters. Wraps the response
-   * (possibly an exception) in a JSONObject.
-   *
-   * @param parameters {@code Bundle} containing the parameters
-   * @return result
-   * @throws Throwable
-   */
-  public Object invoke(SnippetManager manager, final Bundle parameters) throws Throwable {
-    final Annotation annotations[][] = getParameterAnnotations();
-    final Class<?>[] parameterTypes = getMethod().getParameterTypes();
-    final Object[] args = new Object[parameterTypes.length];
-
-    for (int i = 0; i < parameterTypes.length; i++) {
-      Class<?> parameterType = parameterTypes[i];
-      String parameterName = getName(annotations[i]);
-      if (i < parameterTypes.length) {
-        args[i] = convertParameter(parameters, parameterType, parameterName);
-      } else if (MethodDescriptor.hasDefaultValue(annotations[i])) {
-        args[i] = MethodDescriptor.getDefaultValue(parameterType, annotations[i]);
-      } else {
-        throw new RpcError("Argument " + (i + 1) + " is not present");
-      }
-    }
-    return invoke(manager, args);
-  }
-
-  private Object invoke(SnippetManager manager, Object[] args) throws Throwable{
-    Object result = null;
+  private Object invoke(SnippetManager manager, Object[] args) throws Throwable {
+    Object result;
     try {
       result = manager.invoke(mClass, mMethod, args);
     } catch (Throwable t) {
@@ -151,8 +118,6 @@
   static Object convertParameter(final JSONArray parameters, int index, Type type)
       throws JSONException, RpcError {
     try {
-      // Log.d("sl4a", parameters.toString());
-      // Log.d("sl4a", type.toString());
       // 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)) {
@@ -204,41 +169,6 @@
     }
   }
 
-  private Object convertParameter(Bundle bundle, Class<?> type, String name) {
-    Object param = null;
-    if (type.isAssignableFrom(Boolean.class)) {
-      param = bundle.getBoolean(name, false);
-    }
-    if (type.isAssignableFrom(Boolean[].class)) {
-      param = bundle.getBooleanArray(name);
-    }
-    if (type.isAssignableFrom(String.class)) {
-      param = bundle.getString(name);
-    }
-    if (type.isAssignableFrom(String[].class)) {
-      param = bundle.getStringArray(name);
-    }
-    if (type.isAssignableFrom(Integer.class)) {
-      param = bundle.getInt(name, 0);
-    }
-    if (type.isAssignableFrom(Integer[].class)) {
-      param = bundle.getIntArray(name);
-    }
-    if (type.isAssignableFrom(Bundle.class)) {
-      param = bundle.getBundle(name);
-    }
-    if (type.isAssignableFrom(Parcelable.class)) {
-      param = bundle.getParcelable(name);
-    }
-    if (type.isAssignableFrom(Parcelable[].class)) {
-      param = bundle.getParcelableArray(name);
-    }
-    if (type.isAssignableFrom(Intent.class)) {
-      param = bundle.getParcelable(name);
-    }
-    return param;
-  }
-
   public static Object buildIntent(JSONObject jsonObject) throws JSONException {
     Intent intent = new Intent();
     if (jsonObject.has("action")) {
@@ -270,18 +200,7 @@
     return intent;
   }
 
-  public Method getMethod() {
-    return mMethod;
-  }
-
-  public Class<? extends Snippet> getDeclaringClass() {
-    return mClass;
-  }
-
   public String getName() {
-    if (mMethod.isAnnotationPresent(RpcName.class)) {
-      return mMethod.getAnnotation(RpcName.class).name();
-    }
     return mMethod.getName();
   }
 
@@ -289,308 +208,28 @@
     return mMethod.getGenericParameterTypes();
   }
 
-  public Annotation[][] getParameterAnnotations() {
-    return mMethod.getParameterAnnotations();
-  }
-
   /**
    * Returns a human-readable help text for this RPC, based on annotations in the source code.
    *
    * @return derived help string
    */
   public String getHelp() {
-    StringBuilder helpBuilder = new StringBuilder();
-    Rpc rpcAnnotation = mMethod.getAnnotation(Rpc.class);
-
-    helpBuilder.append(mMethod.getName());
-    helpBuilder.append("(");
-    final Class<?>[] parameterTypes = mMethod.getParameterTypes();
-    final Type[] genericParameterTypes = mMethod.getGenericParameterTypes();
-    final Annotation[][] annotations = mMethod.getParameterAnnotations();
+    StringBuilder paramBuilder = new StringBuilder();
+    Class<?>[] parameterTypes = mMethod.getParameterTypes();
     for (int i = 0; i < parameterTypes.length; i++) {
-      if (i == 0) {
-        helpBuilder.append("\n  ");
-      } else {
-        helpBuilder.append(",\n  ");
+      if (i != 0) {
+        paramBuilder.append(", ");
       }
-
-      helpBuilder.append(getHelpForParameter(genericParameterTypes[i], annotations[i]));
+      paramBuilder.append(parameterTypes[i].getSimpleName());
     }
-    helpBuilder.append(")\n\n");
-    helpBuilder.append(rpcAnnotation.description());
-    if (!rpcAnnotation.returns().equals("")) {
-      helpBuilder.append("\n");
-      helpBuilder.append("\nReturns:\n  ");
-      helpBuilder.append(rpcAnnotation.returns());
-    }
-
-    if (mMethod.isAnnotationPresent(RpcStartEvent.class)) {
-      String eventName = mMethod.getAnnotation(RpcStartEvent.class).value();
-      helpBuilder.append(String.format("\n\nGenerates \"%s\" events.", eventName));
-    }
-
-    if (mMethod.isAnnotationPresent(RpcDeprecated.class)) {
-      String replacedBy = mMethod.getAnnotation(RpcDeprecated.class).value();
-      String release = mMethod.getAnnotation(RpcDeprecated.class).release();
-      helpBuilder.append(String.format("\n\nDeprecated in %s! Please use %s instead.", release,
-          replacedBy));
-    }
-
-    return helpBuilder.toString();
-  }
-
-  /**
-   * Returns the help string for one particular parameter. This respects optional parameters.
-   *
-   * @param parameterType
-   *          (generic) type of the parameter
-   * @param annotations
-   *          annotations of the parameter, may be null
-   * @return string describing the parameter based on source code annotations
-   */
-  private static String getHelpForParameter(Type parameterType, Annotation[] annotations) {
-    StringBuilder result = new StringBuilder();
-
-    appendTypeName(result, parameterType);
-    result.append(" ");
-    result.append(getName(annotations));
-    if (hasDefaultValue(annotations)) {
-      result.append("[optional");
-      if (hasExplicitDefaultValue(annotations)) {
-        result.append(", default " + getDefaultValue(parameterType, annotations));
-      }
-      result.append("]");
-    }
-
-    String description = getDescription(annotations);
-    if (description.length() > 0) {
-      result.append(": ");
-      result.append(description);
-    }
-
-    return result.toString();
-  }
-
-  /**
-   * Appends the name of the given type to the {@link StringBuilder}.
-   *
-   * @param builder
-   *          string builder to append to
-   * @param type
-   *          type whose name to append
-   */
-  private static void appendTypeName(final StringBuilder builder, final Type type) {
-    if (type instanceof Class<?>) {
-      builder.append(((Class<?>) type).getSimpleName());
-    } else {
-      ParameterizedType parametrizedType = (ParameterizedType) type;
-      builder.append(((Class<?>) parametrizedType.getRawType()).getSimpleName());
-      builder.append("<");
-
-      Type[] arguments = parametrizedType.getActualTypeArguments();
-      for (int i = 0; i < arguments.length; i++) {
-        if (i > 0) {
-          builder.append(", ");
-        }
-        appendTypeName(builder, arguments[i]);
-      }
-      builder.append(">");
-    }
-  }
-
-  /**
-   * Returns parameter descriptors suitable for the RPC call text representation.
-   *
-   * <p>
-   * Uses parameter value, default value or name, whatever is available first.
-   *
-   * @return an array of parameter descriptors
-   */
-  public ParameterDescriptor[] getParameterValues(String[] values) {
-    Type[] parameterTypes = mMethod.getGenericParameterTypes();
-    Annotation[][] parametersAnnotations = mMethod.getParameterAnnotations();
-    ParameterDescriptor[] parameters = new ParameterDescriptor[parametersAnnotations.length];
-    for (int index = 0; index < parameters.length; index++) {
-      String value;
-      if (index < values.length) {
-        value = values[index];
-      } else if (hasDefaultValue(parametersAnnotations[index])) {
-        Object defaultValue = getDefaultValue(parameterTypes[index], parametersAnnotations[index]);
-        if (defaultValue == null) {
-          value = null;
-        } else {
-          value = String.valueOf(defaultValue);
-        }
-      } else {
-        value = getName(parametersAnnotations[index]);
-      }
-      parameters[index] = new ParameterDescriptor(value, parameterTypes[index]);
-    }
-    return parameters;
-  }
-
-  /**
-   * Returns parameter hints.
-   *
-   * @return an array of parameter hints
-   */
-  public String[] getParameterHints() {
-    Annotation[][] parametersAnnotations = mMethod.getParameterAnnotations();
-    String[] hints = new String[parametersAnnotations.length];
-    for (int index = 0; index < hints.length; index++) {
-      String name = getName(parametersAnnotations[index]);
-      String description = getDescription(parametersAnnotations[index]);
-      String hint = "No paramenter description.";
-      if (!name.equals("") && !description.equals("")) {
-        hint = name + ": " + description;
-      } else if (!name.equals("")) {
-        hint = name;
-      } else if (!description.equals("")) {
-        hint = description;
-      }
-      hints[index] = hint;
-    }
-    return hints;
-  }
-
-  /**
-   * Extracts the formal parameter name from an annotation.
-   *
-   * @param annotations
-   *          the annotations of the parameter
-   * @return the formal name of the parameter
-   */
-  private static String getName(Annotation[] annotations) {
-    for (Annotation a : annotations) {
-      if (a instanceof RpcParameter) {
-        return ((RpcParameter) a).name();
-      }
-    }
-    throw new IllegalStateException("No parameter name");
-  }
-
-  /**
-   * Extracts the parameter description from its annotations.
-   *
-   * @param annotations
-   *          the annotations of the parameter
-   * @return the description of the parameter
-   */
-  private static String getDescription(Annotation[] annotations) {
-    for (Annotation a : annotations) {
-      if (a instanceof RpcParameter) {
-        return ((RpcParameter) a).description();
-      }
-    }
-    throw new IllegalStateException("No parameter description");
-  }
-
-  /**
-   * Returns the default value for a specific parameter.
-   *
-   * @param parameterType
-   *          parameterType
-   * @param annotations
-   *          annotations of the parameter
-   */
-  public static Object getDefaultValue(Type parameterType, Annotation[] annotations) {
-    for (Annotation a : annotations) {
-      if (a instanceof RpcDefault) {
-        RpcDefault defaultAnnotation = (RpcDefault) a;
-        Converter<?> converter = converterFor(parameterType, defaultAnnotation.converter());
-        return converter.convert(defaultAnnotation.value());
-      } else if (a instanceof RpcOptional) {
-        return null;
-      }
-    }
-    throw new IllegalStateException("No default value for " + parameterType);
-  }
-
-  @SuppressWarnings("rawtypes")
-  private static Converter<?> converterFor(Type parameterType,
-      Class<? extends Converter> converterClass) {
-    if (converterClass == Converter.class) {
-      Converter<?> converter = sConverters.get(parameterType);
-      if (converter == null) {
-        throw new IllegalArgumentException("No predefined converter found for " + parameterType);
-      }
-      return converter;
-    }
-    try {
-      Constructor<?> constructor = converterClass.getConstructor(new Class<?>[0]);
-      return (Converter<?>) constructor.newInstance(new Object[0]);
-    } catch (Exception e) {
-      throw new IllegalArgumentException("Cannot create converter from "
-          + converterClass.getCanonicalName());
-    }
-  }
-
-  /**
-   * Determines whether or not this parameter has default value.
-   *
-   * @param annotations
-   *          annotations of the parameter
-   */
-  public static boolean hasDefaultValue(Annotation[] annotations) {
-    for (Annotation a : annotations) {
-      if (a instanceof RpcDefault || a instanceof RpcOptional) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  /**
-   * Returns whether the default value is specified for a specific parameter.
-   *
-   * @param annotations
-   *          annotations of the parameter
-   */
-  //@VisibleForTesting
-  static boolean hasExplicitDefaultValue(Annotation[] annotations) {
-    for (Annotation a : annotations) {
-      if (a instanceof RpcDefault) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  /** Returns the converters for {@code String}, {@code Integer} and {@code Boolean}. */
-  private static Map<Class<?>, Converter<?>> populateConverters() {
-    Map<Class<?>, Converter<?>> converters = new HashMap<Class<?>, Converter<?>>();
-    converters.put(String.class, new Converter<String>() {
-      @Override
-      public String convert(String value) {
-        return value;
-      }
-    });
-    converters.put(Integer.class, new Converter<Integer>() {
-      @Override
-      public Integer convert(String input) {
-        try {
-          return Integer.decode(input);
-        } catch (NumberFormatException e) {
-          throw new IllegalArgumentException("'" + input + "' is not an integer");
-        }
-      }
-    });
-    converters.put(Boolean.class, new Converter<Boolean>() {
-      @Override
-      public Boolean convert(String input) {
-        if (input == null) {
-          return null;
-        }
-        input = input.toLowerCase();
-        if (input.equals("true")) {
-          return Boolean.TRUE;
-        }
-        if (input.equals("false")) {
-          return Boolean.FALSE;
-        }
-        throw new IllegalArgumentException("'" + input + "' is not a boolean");
-      }
-    });
-    return converters;
+    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;
   }
 }
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/ParameterDescriptor.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/ParameterDescriptor.java
deleted file mode 100644
index 55e0151..0000000
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/ParameterDescriptor.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2016 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.google.android.mobly.snippet.rpc;
-
-import java.lang.reflect.Type;
-
-/**
- * RPC parameter description.
- *
- */
-public final class ParameterDescriptor {
-  private final String value;
-  private final Type type;
-
-  public ParameterDescriptor(String value, Type type) {
-    this.value = value;
-    this.type = type;
-  }
-
-  public String getValue() {
-    return value;
-  }
-
-  public Type getType() {
-    return type;
-  }
-}
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 31a5364..fa32e9f 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
@@ -35,9 +35,4 @@
    * Returns brief description of the function. Should be limited to one or two sentences.
    */
   String description();
-
-  /**
-   * Gives a brief description of the functions return value (and the underlying data structure).
-   */
-  String returns() default "";
 }
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcDefault.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcDefault.java
deleted file mode 100644
index bdf1d28..0000000
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcDefault.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2016 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.google.android.mobly.snippet.rpc;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Use this annotation to mark an RPC parameter that have a default value.
- *
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.PARAMETER)
-@Documented
-public @interface RpcDefault {
-  /** The default value of the RPC parameter. */
-  public String value();
-
-  @SuppressWarnings("rawtypes")
-  public Class<? extends Converter> converter() default Converter.class;
-}
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcDeprecated.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcDeprecated.java
deleted file mode 100644
index bbf6c6c..0000000
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcDeprecated.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2016 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.google.android.mobly.snippet.rpc;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Use this annotation to mark RPC method as deprecated.
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.METHOD)
-@Documented
-public @interface RpcDeprecated {
-  /** The method that replaced this one. */
-  public String value();
-
-  /** Release of SL4A when deprecation occurred. */
-  public String release() default "r4";
-}
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 c7e6563..d58a226 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
@@ -28,5 +28,5 @@
 @Documented
 public @interface RpcMinSdk {
   /** Minimum SDK Level. */
-  public int value();
+  int value();
 }
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcName.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcName.java
deleted file mode 100644
index 02052ea..0000000
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcName.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2016 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.google.android.mobly.snippet.rpc;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Use this annotation to mark an RPC parameter that have a default value.
- *
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.METHOD)
-@Documented
-public @interface RpcName {
-  /** The default value of the RPC parameter. */
-  public String name();
-}
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcOptional.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcOptional.java
deleted file mode 100644
index 4e6125b..0000000
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcOptional.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2016 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.google.android.mobly.snippet.rpc;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Use this annotation to mark RPC parameter as optional.
- *
- * <p>
- * The parameter marked as optional has no explicit default value. {@code null} is used as default
- * value.
- *
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.PARAMETER)
-@Documented
-public @interface RpcOptional {
-}
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcParameter.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcParameter.java
deleted file mode 100644
index 4752164..0000000
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcParameter.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2016 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.google.android.mobly.snippet.rpc;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * An annotation that is used to document the parameters of an RPC.
- *
- *
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.PARAMETER)
-@Documented
-public @interface RpcParameter {
-  /**
-   * The name of the formal parameter. This should be in agreement with the java code.
-   */
-  public String name();
-
-  /**
-   * Description of the RPC. This should be a short descriptive statement without a full stop, such
-   * as 'disables the WiFi mode'.
-   */
-  public String description() default "";
-}
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcStartEvent.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcStartEvent.java
deleted file mode 100644
index f23a6a2..0000000
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/RpcStartEvent.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2016 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.google.android.mobly.snippet.rpc;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Use this annotation to mark an RPC as one that starts generating events.
- *
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.METHOD)
-@Documented
-public @interface RpcStartEvent {
-  /** The name of the event that is generated. */
-  public String 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 23a1e89..eaadf66 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
@@ -53,8 +53,8 @@
   private Thread mServerThread;
 
   public interface SimpleServerObserver {
-    public void onConnect();
-    public void onDisconnect();
+    void onConnect();
+    void onDisconnect();
   }
 
   protected abstract void handleConnection(Socket socket) throws Exception;
@@ -217,47 +217,6 @@
     return InetSocketAddress.createUnresolved(mServer.getInetAddress().getHostAddress(), boundPort);
   }
 
-  /**
-   * data Starts the RPC server bound to the public facing address.
-   *
-   * @param port
-   *          the port to bind to or 0 to pick any unused port
-   *
-   * @return the port that the server is bound to
-   */
-  public InetSocketAddress startPublic(int port) {
-    InetAddress address;
-    try {
-      // address = getPublicInetAddress();
-      address = null;
-      mServer = new ServerSocket(port, 5 /* backlog */, address);
-    } catch (Exception e) {
-      Log.e("Failed to start server.", e);
-      return null;
-    }
-    int boundPort = start();
-    return InetSocketAddress.createUnresolved(mServer.getInetAddress().getHostAddress(), boundPort);
-  }
-
-  /**
-   * data Starts the RPC server bound to all interfaces
-   *
-   * @param port
-   *          the port to bind to or 0 to pick any unused port
-   *
-   * @return the port that the server is bound to
-   */
-  public InetSocketAddress startAllInterfaces(int port) {
-    try {
-      mServer = new ServerSocket(port, 5 /* backlog */);
-    } catch (Exception e) {
-      Log.e("Failed to start server.", e);
-      return null;
-    }
-    int boundPort = start();
-    return InetSocketAddress.createUnresolved(mServer.getInetAddress().getHostAddress(), boundPort);
-  }
-
   private int start() {
     mServerThread = new Thread() {
       @Override
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/SnippetManager.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/SnippetManager.java
index 57dab7a..cc4c9f4 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/SnippetManager.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/SnippetManager.java
@@ -21,8 +21,12 @@
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
 
 import com.google.android.mobly.snippet.util.Log;
 
@@ -77,6 +81,10 @@
         return mKnownRpcs.get(methodName);
     }
 
+    public SortedSet<String> getMethodNames() {
+        return new TreeSet<>(mKnownRpcs.keySet());
+    }
+
     public Object invoke(Class<? extends Snippet> clazz, Method method, Object[] args)
             throws Exception {
         Snippet object = get(clazz);
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/SnippetManagerFactory.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/SnippetManagerFactory.java
index 68d5252..f1d16b2 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/SnippetManagerFactory.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/SnippetManagerFactory.java
@@ -19,7 +19,6 @@
 import java.util.Map;
 
 public interface SnippetManagerFactory {
-  public SnippetManager create(Integer UID);
-
-  public 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/service/SnippetService.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/service/SnippetService.java
index a53eca6..8789090 100644
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/service/SnippetService.java
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/service/SnippetService.java
@@ -105,7 +105,7 @@
     }
 
     private AndroidProxy launchServer(Intent intent) {
-        AndroidProxy androidProxy = new AndroidProxy(this, false /* requiresHandshake */);
+        AndroidProxy androidProxy = new AndroidProxy(this);
         int servicePort = intent.getIntExtra(Constants.EXTRA_SERVICE_PORT, 0);
         if (servicePort == 0) {
             throw new IllegalArgumentException(