aboutsummaryrefslogtreecommitdiff
path: root/third_party/sl4a/src/main/java/com
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/sl4a/src/main/java/com')
-rw-r--r--third_party/sl4a/src/main/java/com/google/android/mobly/snippet/manager/ReflectionSnippetManagerFactory.java97
-rw-r--r--third_party/sl4a/src/main/java/com/google/android/mobly/snippet/manager/SnippetManager.java83
-rw-r--r--third_party/sl4a/src/main/java/com/google/android/mobly/snippet/manager/SnippetManagerFactory.java25
-rw-r--r--third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/AndroidProxy.java6
-rw-r--r--third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/JsonRpcResult.java14
-rw-r--r--third_party/sl4a/src/main/java/com/google/android/mobly/snippet/rpc/JsonRpcServer.java66
-rw-r--r--third_party/sl4a/src/main/java/com/google/android/mobly/snippet/schedulerpc/ScheduleRpcSnippet.java45
-rw-r--r--third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/RpcUtil.java138
8 files changed, 288 insertions, 186 deletions
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
deleted file mode 100644
index 5e4259d..0000000
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/manager/ReflectionSnippetManagerFactory.java
+++ /dev/null
@@ -1,97 +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.manager;
-
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import com.google.android.mobly.snippet.Snippet;
-import com.google.android.mobly.snippet.event.EventSnippet;
-import com.google.android.mobly.snippet.util.Log;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-public class ReflectionSnippetManagerFactory implements SnippetManagerFactory {
- private static final String METADATA_TAG_NAME = "mobly-snippets";
-
- private final Context mContext;
- private final Set<Class<? extends Snippet>> mClasses;
- private final Map<Integer, SnippetManager> mSnippetManagers;
-
- public ReflectionSnippetManagerFactory(Context context) {
- mContext = context;
- mClasses = loadSnippets();
- mSnippetManagers = new HashMap<>();
- }
-
- @Override
- public SnippetManager create(Integer UID) {
- SnippetManager manager = new SnippetManager(mClasses);
- mSnippetManagers.put(UID, manager);
- return manager;
- }
-
- @Override
- public Map<Integer, SnippetManager> getSnippetManagers() {
- return Collections.unmodifiableMap(mSnippetManagers);
- }
-
- private Set<Class<? extends Snippet>> loadSnippets() {
- ApplicationInfo appInfo;
- try {
- appInfo =
- mContext.getPackageManager()
- .getApplicationInfo(
- mContext.getPackageName(), PackageManager.GET_META_DATA);
- } catch (PackageManager.NameNotFoundException e) {
- throw new IllegalStateException(
- "Failed to find ApplicationInfo with package name: "
- + mContext.getPackageName());
- }
- Bundle metadata = appInfo.metaData;
- String snippets = metadata.getString(METADATA_TAG_NAME);
- if (snippets == null) {
- throw new IllegalStateException(
- "AndroidManifest.xml does not contain a <metadata> tag with "
- + "name=\""
- + METADATA_TAG_NAME
- + "\"");
- }
- String[] snippetClassNames = snippets.split("\\s*,\\s*");
- Set<Class<? extends Snippet>> receiverSet = new HashSet<>();
- /** Add the event snippet class which is provided within the Snippet Lib. */
- receiverSet.add(EventSnippet.class);
- for (String snippetClassName : snippetClassNames) {
- try {
- Log.i("Trying to load Snippet class: " + snippetClassName);
- Class<?> snippetClass = Class.forName(snippetClassName);
- receiverSet.add((Class<? extends Snippet>) snippetClass);
- } catch (ClassNotFoundException e) {
- Log.e("Failed to find class " + snippetClassName);
- throw new RuntimeException(e);
- }
- }
- if (receiverSet.isEmpty()) {
- throw new IllegalStateException("Found no subclasses of Snippet.");
- }
- return receiverSet;
- }
-}
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 ff0aec3..66e33b3 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
@@ -16,11 +16,17 @@
package com.google.android.mobly.snippet.manager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+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.event.EventSnippet;
import com.google.android.mobly.snippet.rpc.MethodDescriptor;
import com.google.android.mobly.snippet.rpc.RpcMinSdk;
import com.google.android.mobly.snippet.rpc.RunOnUiThread;
+import com.google.android.mobly.snippet.schedulerpc.ScheduleRpcSnippet;
import com.google.android.mobly.snippet.util.Log;
import com.google.android.mobly.snippet.util.MainThread;
import com.google.android.mobly.snippet.util.SnippetLibException;
@@ -30,18 +36,24 @@ import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.Callable;
public class SnippetManager {
+ private static final String METADATA_TAG_NAME = "mobly-snippets";
private final Map<Class<? extends Snippet>, Snippet> mSnippets;
/** A map of strings to known RPCs. */
private final Map<String, MethodDescriptor> mKnownRpcs;
- public SnippetManager(Collection<Class<? extends Snippet>> classList) {
+ private static SnippetManager sInstance = null;
+ private boolean mShutdown = false;
+
+ private SnippetManager(Collection<Class<? extends Snippet>> classList) {
// Synchronized for multiple connections on the same session. Can't use ConcurrentHashMap
// because we have to put in a value of 'null' before the class is constructed, but
// ConcurrentHashMap does not allow null values.
@@ -65,6 +77,25 @@ public class SnippetManager {
mKnownRpcs = Collections.unmodifiableMap(knownRpcs);
}
+ public static synchronized SnippetManager initSnippetManager(Context context) {
+ if (sInstance != null) {
+ throw new IllegalStateException("SnippetManager should not be re-initialized");
+ }
+ Collection<Class<? extends Snippet>> classList = findSnippetClassesFromMetadata(context);
+ sInstance = new SnippetManager(classList);
+ return sInstance;
+ }
+
+ public static SnippetManager getInstance() {
+ if (sInstance == null) {
+ throw new IllegalStateException("getInstance() called before init()");
+ }
+ if (sInstance.isShutdown()) {
+ throw new IllegalStateException("shutdown() called before getInstance()");
+ }
+ return sInstance;
+ }
+
public MethodDescriptor getMethodDescriptor(String methodName) {
return mKnownRpcs.get(methodName);
}
@@ -114,6 +145,56 @@ public class SnippetManager {
entry.getValue().shutdown();
}
}
+ mSnippets.clear();
+ mKnownRpcs.clear();
+ mShutdown = true;
+ }
+
+ public boolean isShutdown() {
+ return mShutdown;
+ }
+
+ private static Set<Class<? extends Snippet>> findSnippetClassesFromMetadata(Context context) {
+ ApplicationInfo appInfo;
+ try {
+ appInfo =
+ context.getPackageManager()
+ .getApplicationInfo(
+ context.getPackageName(), PackageManager.GET_META_DATA);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalStateException(
+ "Failed to find ApplicationInfo with package name: "
+ + context.getPackageName());
+ }
+ Bundle metadata = appInfo.metaData;
+ String snippets = metadata.getString(METADATA_TAG_NAME);
+ if (snippets == null) {
+ throw new IllegalStateException(
+ "AndroidManifest.xml does not contain a <metadata> tag with "
+ + "name=\""
+ + METADATA_TAG_NAME
+ + "\"");
+ }
+ String[] snippetClassNames = snippets.split("\\s*,\\s*");
+ Set<Class<? extends Snippet>> receiverSet = new HashSet<>();
+ /** Add the event snippet class which is provided within the Snippet Lib. */
+ receiverSet.add(EventSnippet.class);
+ /** Add the schedule RPC snippet class which is provided within the Snippet Lib. */
+ receiverSet.add(ScheduleRpcSnippet.class);
+ for (String snippetClassName : snippetClassNames) {
+ try {
+ Log.i("Trying to load Snippet class: " + snippetClassName);
+ Class<?> snippetClass = Class.forName(snippetClassName);
+ receiverSet.add((Class<? extends Snippet>) snippetClass);
+ } catch (ClassNotFoundException e) {
+ Log.e("Failed to find class " + snippetClassName);
+ throw new RuntimeException(e);
+ }
+ }
+ if (receiverSet.isEmpty()) {
+ throw new IllegalStateException("Found no subclasses of Snippet.");
+ }
+ return receiverSet;
}
private Snippet get(Class<? extends Snippet> clazz) throws Exception {
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
deleted file mode 100644
index 50a3552..0000000
--- a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/manager/SnippetManagerFactory.java
+++ /dev/null
@@ -1,25 +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.manager;
-
-import java.util.Map;
-
-public interface SnippetManagerFactory {
- 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 cb2e772..9428c82 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,18 +17,14 @@
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;
public class AndroidProxy {
private final JsonRpcServer mJsonRpcServer;
- private final SnippetManagerFactory mSnippetManagerFactory;
public AndroidProxy(Context context) {
- mSnippetManagerFactory = new ReflectionSnippetManagerFactory(context);
- mJsonRpcServer = new JsonRpcServer(mSnippetManagerFactory);
+ mJsonRpcServer = new JsonRpcServer(context);
}
public void startLocal(int port) throws IOException {
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 de8537c..90cf8f9 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
@@ -60,11 +60,7 @@ public class JsonRpcResult {
}
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();
+ String stackTrace = getStackTrace(t);
JSONObject json = new JSONObject();
json.put("id", id);
json.put("result", JSONObject.NULL);
@@ -72,4 +68,12 @@ public class JsonRpcResult {
json.put("error", stackTrace);
return json;
}
+
+ public static String getStackTrace(Throwable throwable) {
+ StringWriter stackTraceWriter = new StringWriter();
+ stackTraceWriter.write("\n-------------- Java Stacktrace ---------------\n");
+ throwable.printStackTrace(new PrintWriter(stackTraceWriter));
+ stackTraceWriter.write("----------------------------------------------");
+ return stackTraceWriter.toString();
+ }
}
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 219c471..1dde423 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
@@ -16,9 +16,10 @@
package com.google.android.mobly.snippet.rpc;
+import android.content.Context;
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 com.google.android.mobly.snippet.util.RpcUtil;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.net.Socket;
@@ -35,33 +36,19 @@ public class JsonRpcServer extends SimpleServer {
private static final String CMD_CLOSE_SESSION = "closeSl4aSession";
private static final String CMD_HELP = "help";
- private final SnippetManagerFactory mSnippetManagerFactory;
+ private final SnippetManager mSnippetManager;
+ private final RpcUtil mRpcUtil;
- /**
- * Construct a {@link JsonRpcServer} connected to the provided {@link SnippetManager}.
- *
- * @param managerFactory the {@link SnippetManager} to register with the server
- */
- public JsonRpcServer(SnippetManagerFactory managerFactory) {
- mSnippetManagerFactory = managerFactory;
+ /** Construct a {@link JsonRpcServer} connected to the provided {@link SnippetManager}. */
+ public JsonRpcServer(Context context) {
+ mSnippetManager = SnippetManager.initSnippetManager(context);
+ mRpcUtil = new RpcUtil();
}
@Override
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());
- if (mgrs.containsKey(UID)) {
- Log.d("Look up existing session");
- receiverManager = mgrs.get(UID);
- } else {
- Log.d("Create a new session");
- receiverManager = mSnippetManagerFactory.create(UID);
- }
- }
+ Log.d("UID " + UID);
String data;
while ((data = reader.readLine()) != null) {
Log.v("Session " + UID + " Received: " + data);
@@ -72,16 +59,13 @@ public class JsonRpcServer extends SimpleServer {
// Handle builtin commands
if (method.equals(CMD_HELP)) {
- help(writer, id, receiverManager, UID);
+ help(writer, id, mSnippetManager, UID);
continue;
} else if (method.equals(CMD_CLOSE_SESSION)) {
Log.d("Got shutdown signal");
synchronized (writer) {
// Shut down all RPC receivers.
- for (SnippetManager manager :
- mSnippetManagerFactory.getSnippetManagers().values()) {
- manager.shutdown();
- }
+ mSnippetManager.shutdown();
// Shut down this client connection. As soon as this happens, the client will
// kill us by triggering the 'stop' action from another instrumentation, so no
@@ -93,35 +77,11 @@ public class JsonRpcServer extends SimpleServer {
// Shut down this server.
shutdown();
- mgrs.clear();
}
return;
}
-
- MethodDescriptor rpc = receiverManager.getMethodDescriptor(method);
- if (rpc == null) {
- send(writer, JsonRpcResult.error(id, new RpcError("Unknown RPC: " + method)), UID);
- continue;
- }
- try {
- /** If calling an {@link AsyncRpc}, put the message ID as the first param. */
- if (rpc.isAsync()) {
- String callbackId = String.format("%d-%d", UID, id);
- JSONArray newParams = new JSONArray();
- newParams.put(callbackId);
- for (int i = 0; i < params.length(); i++) {
- newParams.put(params.get(i));
- }
- Object returnValue = rpc.invoke(receiverManager, newParams);
- send(writer, JsonRpcResult.callback(id, returnValue, callbackId), UID);
- } else {
- Object returnValue = rpc.invoke(receiverManager, params);
- send(writer, JsonRpcResult.result(id, returnValue), UID);
- }
- } catch (Throwable t) {
- Log.e("Invocation error.", t);
- send(writer, JsonRpcResult.error(id, t), UID);
- }
+ JSONObject returnValue = mRpcUtil.invokeRpc(method, params, id, UID);
+ send(writer, returnValue, UID);
}
}
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/schedulerpc/ScheduleRpcSnippet.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/schedulerpc/ScheduleRpcSnippet.java
new file mode 100644
index 0000000..88dea24
--- /dev/null
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/schedulerpc/ScheduleRpcSnippet.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 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.schedulerpc;
+
+import com.google.android.mobly.snippet.Snippet;
+import com.google.android.mobly.snippet.manager.SnippetManager;
+import com.google.android.mobly.snippet.rpc.AsyncRpc;
+import com.google.android.mobly.snippet.util.RpcUtil;
+import org.json.JSONArray;
+
+/** Snippet that provides {@link AsyncRpc} to schedule other RPCs. */
+public class ScheduleRpcSnippet implements Snippet {
+
+ private final SnippetManager mReceiverManager;
+ private final RpcUtil mRpcUtil;
+
+ public ScheduleRpcSnippet() {
+ mReceiverManager = SnippetManager.getInstance();
+ mRpcUtil = new RpcUtil();
+ }
+
+ @AsyncRpc(description = "Delay the given RPC by provided milli-seconds.")
+ public void scheduleRpc(
+ String callbackId, String methodName, long delayTimerMs, JSONArray params)
+ throws Throwable {
+ mRpcUtil.scheduleRpc(callbackId, methodName, delayTimerMs, params);
+ }
+
+ @Override
+ public void shutdown() {}
+}
diff --git a/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/RpcUtil.java b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/RpcUtil.java
new file mode 100644
index 0000000..7eba07f
--- /dev/null
+++ b/third_party/sl4a/src/main/java/com/google/android/mobly/snippet/util/RpcUtil.java
@@ -0,0 +1,138 @@
+/*
+ * 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.util;
+
+import com.google.android.mobly.snippet.event.EventCache;
+import com.google.android.mobly.snippet.event.SnippetEvent;
+import com.google.android.mobly.snippet.manager.SnippetManager;
+import com.google.android.mobly.snippet.rpc.JsonRpcResult;
+import com.google.android.mobly.snippet.rpc.MethodDescriptor;
+import com.google.android.mobly.snippet.rpc.RpcError;
+import java.util.Timer;
+import java.util.TimerTask;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Class that implements APIs to schedule other RPCs.
+ *
+ * <p>If a device is required to be disconnected (e.g., USB power off), no RPCs can be made while
+ * device is offline.
+ *
+ * <p>However, We still need snippet continue to run and execute previously scheduled RPCs
+ *
+ * <p>The return value of the scheduled RPC is cached in {@link EventCache} and can be retrieved
+ * later after device is back online.
+ */
+public class RpcUtil {
+ // RPC ID is used for reporting responses back to the client. However, the results of
+ // scheduled RPCs are reported back to the client via events instead of through synchronous
+ // responses, so the RPC ID is unused. We pass an arbitrary value of 0.
+ private static final int DEFAULT_ID = 0;
+ private final SnippetManager mReceiverManager;
+ private final EventCache mEventCache = EventCache.getInstance();
+
+ public RpcUtil() {
+ mReceiverManager = SnippetManager.getInstance();
+ }
+
+ /**
+ * Schedule given RPC with some delay.
+ *
+ * @param callbackId The callback ID used to cache RPC results.
+ * @param methodName The RPC name to be scheduled.
+ * @param delayMs The delay in ms
+ * @param params Array of the parameters to the RPC
+ */
+ public void scheduleRpc(
+ final String callbackId,
+ final String methodName,
+ final long delayMs,
+ final JSONArray params)
+ throws Throwable {
+ Timer timer = new Timer();
+ TimerTask task =
+ new TimerTask() {
+ @Override
+ public void run() {
+ SnippetEvent event = new SnippetEvent(callbackId, methodName);
+ try {
+ JSONObject obj = invokeRpc(methodName, params, DEFAULT_ID, callbackId);
+ // Cache RPC method return value.
+ for (int i = 0; i < obj.names().length(); i++) {
+ String key = obj.names().getString(i);
+ event.getData().putString(key, obj.get(key).toString());
+ }
+ } catch (JSONException e) {
+ String stackTrace = JsonRpcResult.getStackTrace(e);
+ event.getData().putString("error", stackTrace);
+ } finally {
+ mEventCache.postEvent(event);
+ }
+ }
+ };
+ timer.schedule(task, delayMs);
+ }
+
+ /**
+ * Invoke the RPC.
+ *
+ * @param methodName The RPC name to be invoked.
+ * @param params Array of the parameters to the RPC
+ * @param id The ID that identifies an RPC
+ * @param UID Globally unique session ID.
+ */
+ public JSONObject invokeRpc(String methodName, JSONArray params, int id, Integer UID)
+ throws JSONException {
+ return invokeRpc(methodName, params, id, String.format("%d-%d", UID, id));
+ }
+
+ /**
+ * Invoke the RPC.
+ *
+ * @param methodName The RPC name to be invoked.
+ * @param params Array of the parameters to the RPC
+ * @param id The ID that identifies an RPC
+ * @param callbackId The callback ID used to cache RPC results.
+ */
+ public JSONObject invokeRpc(String methodName, JSONArray params, int id, String callbackId)
+ throws JSONException {
+ MethodDescriptor rpc = mReceiverManager.getMethodDescriptor(methodName);
+ if (rpc == null) {
+ return JsonRpcResult.error(id, new RpcError("Unknown RPC: " + methodName));
+ }
+ try {
+ JSONArray newParams = new JSONArray();
+ /** If calling an {@link AsyncRpc}, put the message ID as the first param. */
+ if (rpc.isAsync()) {
+ newParams.put(callbackId);
+ for (int i = 0; i < params.length(); i++) {
+ newParams.put(params.get(i));
+ }
+ Object returnValue = rpc.invoke(mReceiverManager, newParams);
+ return JsonRpcResult.callback(id, returnValue, callbackId);
+ } else {
+ Object returnValue = rpc.invoke(mReceiverManager, params);
+ return JsonRpcResult.result(id, returnValue);
+ }
+ } catch (Throwable t) {
+ Log.e("Invocation error.", t);
+ return JsonRpcResult.error(id, t);
+ }
+ }
+}