Allow quoted strings from NativeDaemonConnector
Previously we'd only handled quoted strings going into NDC. This
change auto-handles quoted strings in broadcasts and allows
protocol handlers to request de-quoted elements when needed instead
of using the generic split(" ").
bug: 6353048
Change-Id: I8a07be86411063ed1b402294edc399b4cc076da5
diff --git a/services/java/com/android/server/NativeDaemonEvent.java b/services/java/com/android/server/NativeDaemonEvent.java
index d5e9f66..f11ae1d 100644
--- a/services/java/com/android/server/NativeDaemonEvent.java
+++ b/services/java/com/android/server/NativeDaemonEvent.java
@@ -16,6 +16,7 @@
package com.android.server;
+import android.util.Slog;
import com.google.android.collect.Lists;
import java.util.ArrayList;
@@ -32,12 +33,14 @@
private final int mCode;
private final String mMessage;
private final String mRawEvent;
+ private String[] mParsed;
private NativeDaemonEvent(int cmdNumber, int code, String message, String rawEvent) {
mCmdNumber = cmdNumber;
mCode = code;
mMessage = message;
mRawEvent = rawEvent;
+ mParsed = null;
}
public int getCmdNumber() {
@@ -166,4 +169,86 @@
}
return result.toArray(new String[result.size()]);
}
+
+ /**
+ * Find the Nth field of the event.
+ *
+ * This ignores and code or cmdNum, the first return value is given for N=0.
+ * Also understands "\"quoted\" multiword responses" and tries them as a single field
+ */
+ public String getField(int n) {
+ if (mParsed == null) {
+ mParsed = unescapeArgs(mRawEvent);
+ }
+ n += 2; // skip code and command#
+ if (n > mParsed.length) return null;
+ return mParsed[n];
+ }
+
+ public static String[] unescapeArgs(String rawEvent) {
+ final boolean DEBUG_ROUTINE = false;
+ final String LOGTAG = "unescapeArgs";
+ final ArrayList<String> parsed = new ArrayList<String>();
+ final int length = rawEvent.length();
+ int current = 0;
+ int wordEnd = -1;
+ boolean quoted = false;
+
+ if (DEBUG_ROUTINE) Slog.e(LOGTAG, "parsing '" + rawEvent + "'");
+ if (rawEvent.charAt(current) == '\"') {
+ quoted = true;
+ current++;
+ }
+ while (current < length) {
+ // find the end of the word
+ if (quoted) {
+ wordEnd = current;
+ while ((wordEnd = rawEvent.indexOf('\"', wordEnd)) != -1) {
+ if (rawEvent.charAt(wordEnd - 1) != '\\') {
+ break;
+ } else {
+ wordEnd++; // skip this escaped quote and keep looking
+ }
+ }
+ } else {
+ wordEnd = rawEvent.indexOf(' ', current);
+ }
+ // if we didn't find the end-o-word token, take the rest of the string
+ if (wordEnd == -1) wordEnd = length;
+ String word = rawEvent.substring(current, wordEnd);
+ current += word.length();
+ if (!quoted) {
+ word = word.trim();
+ } else {
+ current++; // skip the trailing quote
+ }
+ // unescape stuff within the word
+ word.replace("\\\\", "\\");
+ word.replace("\\\"", "\"");
+
+ if (DEBUG_ROUTINE) Slog.e(LOGTAG, "found '" + word + "'");
+ parsed.add(word);
+
+ // find the beginning of the next word - either of these options
+ int nextSpace = rawEvent.indexOf(' ', current);
+ int nextQuote = rawEvent.indexOf(" \"", current);
+ if (DEBUG_ROUTINE) {
+ Slog.e(LOGTAG, "nextSpace=" + nextSpace + ", nextQuote=" + nextQuote);
+ }
+ if (nextQuote > -1 && nextQuote <= nextSpace) {
+ quoted = true;
+ current = nextQuote + 2;
+ } else {
+ quoted = false;
+ if (nextSpace > -1) {
+ current = nextSpace + 1;
+ }
+ } // else we just start the next word after the current and read til the end
+ if (DEBUG_ROUTINE) {
+ Slog.e(LOGTAG, "next loop - current=" + current +
+ ", length=" + length + ", quoted=" + quoted);
+ }
+ }
+ return parsed.toArray(new String[parsed.size()]);
+ }
}