Move native netd calls to varargs.
Uses argument escaping inside NativeDaemonConnector, using varargs
to separate boundaries. Also introduces Command object to help build
argument lists.
Bug: 5472606
Change-Id: I357979fc19bb0171a056e690064e01b5a7119501
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
index 1e98f93..cc2bcd9 100644
--- a/services/java/com/android/server/NativeDaemonConnector.java
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -29,6 +29,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.charset.Charsets;
import java.util.ArrayList;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
@@ -122,13 +123,15 @@
for (int i = 0; i < count; i++) {
if (buffer[i] == 0) {
- final String rawEvent = new String(buffer, start, i - start);
+ final String rawEvent = new String(
+ buffer, start, i - start, Charsets.UTF_8);
if (LOGD) Slog.d(TAG, "RCV <- " + rawEvent);
try {
final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent(
rawEvent);
if (event.isClassUnsolicited()) {
+ // TODO: migrate to sending NativeDaemonEvent instances
mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage(
event.getCode(), event.getRawEvent()));
} else {
@@ -213,7 +216,7 @@
throw new NativeDaemonConnectorException("missing output stream");
} else {
try {
- mOutputStream.write(builder.toString().getBytes());
+ mOutputStream.write(builder.toString().getBytes(Charsets.UTF_8));
} catch (IOException e) {
throw new NativeDaemonConnectorException("problem sending command", e);
}
@@ -223,9 +226,62 @@
}
/**
- * Issue a command to the native daemon and return the responses.
+ * Issue the given command to the native daemon and return a single expected
+ * response.
+ *
+ * @throws NativeDaemonConnectorException when problem communicating with
+ * native daemon, or if the response matches
+ * {@link NativeDaemonEvent#isClassClientError()} or
+ * {@link NativeDaemonEvent#isClassServerError()}.
*/
- public NativeDaemonEvent[] execute(String cmd, Object... args)
+ public NativeDaemonEvent execute(Command cmd) throws NativeDaemonConnectorException {
+ return execute(cmd.mCmd, cmd.mArguments.toArray());
+ }
+
+ /**
+ * Issue the given command to the native daemon and return a single expected
+ * response.
+ *
+ * @throws NativeDaemonConnectorException when problem communicating with
+ * native daemon, or if the response matches
+ * {@link NativeDaemonEvent#isClassClientError()} or
+ * {@link NativeDaemonEvent#isClassServerError()}.
+ */
+ public NativeDaemonEvent execute(String cmd, Object... args)
+ throws NativeDaemonConnectorException {
+ final NativeDaemonEvent[] events = executeForList(cmd, args);
+ if (events.length != 1) {
+ throw new NativeDaemonConnectorException(
+ "Expected exactly one response, but received " + events.length);
+ }
+ return events[0];
+ }
+
+ /**
+ * Issue the given command to the native daemon and return any
+ * {@link NativeDaemonEvent#isClassContinue()} responses, including the
+ * final terminal response.
+ *
+ * @throws NativeDaemonConnectorException when problem communicating with
+ * native daemon, or if the response matches
+ * {@link NativeDaemonEvent#isClassClientError()} or
+ * {@link NativeDaemonEvent#isClassServerError()}.
+ */
+ public NativeDaemonEvent[] executeForList(Command cmd) throws NativeDaemonConnectorException {
+ return executeForList(cmd.mCmd, cmd.mArguments.toArray());
+ }
+
+ /**
+ * Issue the given command to the native daemon and return any
+ * {@link NativeDaemonEvent#isClassContinue()} responses, including the
+ * final terminal response.
+ *
+ * @throws NativeDaemonConnectorException when problem communicating with
+ * native daemon, or if the response matches
+ * {@link NativeDaemonEvent#isClassClientError()} or
+ * {@link NativeDaemonEvent#isClassServerError()}.
+ */
+ public NativeDaemonEvent[] executeForList(String cmd, Object... args)
throws NativeDaemonConnectorException {
synchronized (mDaemonLock) {
return executeLocked(cmd, args);
@@ -270,7 +326,7 @@
@Deprecated
public ArrayList<String> doCommand(String cmd) throws NativeDaemonConnectorException {
final ArrayList<String> rawEvents = Lists.newArrayList();
- final NativeDaemonEvent[] events = execute(cmd);
+ final NativeDaemonEvent[] events = executeForList(cmd);
for (NativeDaemonEvent event : events) {
rawEvents.add(event.getRawEvent());
}
@@ -281,11 +337,12 @@
* Issues a list command and returns the cooked list of all
* {@link NativeDaemonEvent#getMessage()} which match requested code.
*/
+ @Deprecated
public String[] doListCommand(String cmd, int expectedCode)
throws NativeDaemonConnectorException {
final ArrayList<String> list = Lists.newArrayList();
- final NativeDaemonEvent[] events = execute(cmd);
+ final NativeDaemonEvent[] events = executeForList(cmd);
for (int i = 0; i < events.length - 1; i++) {
final NativeDaemonEvent event = events[i];
final int code = event.getCode();
@@ -351,6 +408,26 @@
}
}
+ /**
+ * Command builder that handles argument list building.
+ */
+ public static class Command {
+ private String mCmd;
+ private ArrayList<Object> mArguments = Lists.newArrayList();
+
+ public Command(String cmd, Object... args) {
+ mCmd = cmd;
+ for (Object arg : args) {
+ appendArg(arg);
+ }
+ }
+
+ public Command appendArg(Object arg) {
+ mArguments.add(arg);
+ return this;
+ }
+ }
+
/** {@inheritDoc} */
public void monitor() {
synchronized (mDaemonLock) { }