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
This commit is contained in:
Jeff Sharkey
2011-11-30 18:13:54 -08:00
parent cd257fbaaf
commit 36ff7058f6
2 changed files with 112 additions and 6 deletions

View File

@@ -29,6 +29,7 @@ import com.google.android.collect.Lists;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.charset.Charsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
@@ -122,13 +123,15 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
if (buffer[i] == 0) { 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); if (LOGD) Slog.d(TAG, "RCV <- " + rawEvent);
try { try {
final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent( final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent(
rawEvent); rawEvent);
if (event.isClassUnsolicited()) { if (event.isClassUnsolicited()) {
// TODO: migrate to sending NativeDaemonEvent instances
mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage( mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage(
event.getCode(), event.getRawEvent())); event.getCode(), event.getRawEvent()));
} else { } else {
@@ -213,7 +216,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo
throw new NativeDaemonConnectorException("missing output stream"); throw new NativeDaemonConnectorException("missing output stream");
} else { } else {
try { try {
mOutputStream.write(builder.toString().getBytes()); mOutputStream.write(builder.toString().getBytes(Charsets.UTF_8));
} catch (IOException e) { } catch (IOException e) {
throw new NativeDaemonConnectorException("problem sending command", 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 { throws NativeDaemonConnectorException {
synchronized (mDaemonLock) { synchronized (mDaemonLock) {
return executeLocked(cmd, args); return executeLocked(cmd, args);
@@ -270,7 +326,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo
@Deprecated @Deprecated
public ArrayList<String> doCommand(String cmd) throws NativeDaemonConnectorException { public ArrayList<String> doCommand(String cmd) throws NativeDaemonConnectorException {
final ArrayList<String> rawEvents = Lists.newArrayList(); final ArrayList<String> rawEvents = Lists.newArrayList();
final NativeDaemonEvent[] events = execute(cmd); final NativeDaemonEvent[] events = executeForList(cmd);
for (NativeDaemonEvent event : events) { for (NativeDaemonEvent event : events) {
rawEvents.add(event.getRawEvent()); 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 * Issues a list command and returns the cooked list of all
* {@link NativeDaemonEvent#getMessage()} which match requested code. * {@link NativeDaemonEvent#getMessage()} which match requested code.
*/ */
@Deprecated
public String[] doListCommand(String cmd, int expectedCode) public String[] doListCommand(String cmd, int expectedCode)
throws NativeDaemonConnectorException { throws NativeDaemonConnectorException {
final ArrayList<String> list = Lists.newArrayList(); 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++) { for (int i = 0; i < events.length - 1; i++) {
final NativeDaemonEvent event = events[i]; final NativeDaemonEvent event = events[i];
final int code = event.getCode(); 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<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} */ /** {@inheritDoc} */
public void monitor() { public void monitor() {
synchronized (mDaemonLock) { } synchronized (mDaemonLock) { }

View File

@@ -16,6 +16,10 @@
package com.android.server; package com.android.server;
import com.google.android.collect.Lists;
import java.util.ArrayList;
/** /**
* Parsed event from native side of {@link NativeDaemonConnector}. * Parsed event from native side of {@link NativeDaemonConnector}.
*/ */
@@ -88,6 +92,17 @@ public class NativeDaemonEvent {
return mCode >= 600 && mCode < 700; 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. * Parse the given raw event into {@link NativeDaemonEvent} instance.
* *
@@ -110,4 +125,18 @@ public class NativeDaemonEvent {
final String message = rawEvent.substring(splitIndex + 1); final String message = rawEvent.substring(splitIndex + 1);
return new NativeDaemonEvent(code, message, rawEvent); 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<String> result = Lists.newArrayList();
for (NativeDaemonEvent event : events) {
if (event.getCode() == matchCode) {
result.add(event.getMessage());
}
}
return result.toArray(new String[result.size()]);
}
} }