diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 1e98f938fc..cc2bcd9235 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -29,6 +29,7 @@ import com.google.android.collect.Lists; 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 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo 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 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo 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 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } /** - * 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 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo @Deprecated public ArrayList doCommand(String cmd) throws NativeDaemonConnectorException { final ArrayList 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 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo * 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 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 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } } + /** + * Command builder that handles argument list building. + */ + public static class Command { + private String mCmd; + private ArrayList 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) { } diff --git a/services/java/com/android/server/NativeDaemonEvent.java b/services/java/com/android/server/NativeDaemonEvent.java index b1d078843d..62084c072a 100644 --- a/services/java/com/android/server/NativeDaemonEvent.java +++ b/services/java/com/android/server/NativeDaemonEvent.java @@ -16,6 +16,10 @@ package com.android.server; +import com.google.android.collect.Lists; + +import java.util.ArrayList; + /** * Parsed event from native side of {@link NativeDaemonConnector}. */ @@ -88,6 +92,17 @@ public class NativeDaemonEvent { return mCode >= 600 && mCode < 700; } + /** + * Verify this event matches the given code. + * + * @throws IllegalStateException if {@link #getCode()} doesn't match. + */ + public void checkCode(int code) { + if (mCode != code) { + throw new IllegalStateException("Expected " + code + " but was: " + this); + } + } + /** * Parse the given raw event into {@link NativeDaemonEvent} instance. * @@ -110,4 +125,18 @@ public class NativeDaemonEvent { final String message = rawEvent.substring(splitIndex + 1); return new NativeDaemonEvent(code, message, rawEvent); } + + /** + * Filter the given {@link NativeDaemonEvent} list, returning + * {@link #getMessage()} for any events matching the requested code. + */ + public static String[] filterMessageList(NativeDaemonEvent[] events, int matchCode) { + final ArrayList result = Lists.newArrayList(); + for (NativeDaemonEvent event : events) { + if (event.getCode() == matchCode) { + result.add(event.getMessage()); + } + } + return result.toArray(new String[result.size()]); + } }