diff options
author | Paul Hu <paulhu@google.com> | 2022-04-12 07:37:16 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2022-04-12 07:37:16 +0000 |
commit | 631c2387a60717fde7133b4ac2b1d226b5c7ded1 (patch) | |
tree | 9f1e2443c2aabf4d53f88b395e1f8ed5c8727b4d | |
parent | 03c8a7a6a19549fb22507f2ec503dc43f9cfe3b9 (diff) | |
parent | cee953bd09bea535745b372c8ceddf9985cdad21 (diff) | |
download | Connectivity-631c2387a60717fde7133b4ac2b1d226b5c7ded1.tar.gz |
Merge "Remove NativeDaemonConnector relevant files"
7 files changed, 0 insertions, 1180 deletions
diff --git a/service-t/src/com/android/server/INativeDaemonConnectorCallbacks.java b/service-t/src/com/android/server/INativeDaemonConnectorCallbacks.java deleted file mode 100644 index 0cf9dcde01..0000000000 --- a/service-t/src/com/android/server/INativeDaemonConnectorCallbacks.java +++ /dev/null @@ -1,25 +0,0 @@ - -/* - * Copyright (C) 2007 The Android Open Source Project - * - * 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.android.server; - -interface INativeDaemonConnectorCallbacks { - - void onDaemonConnected(); - boolean onCheckHoldWakeLock(int code); - boolean onEvent(int code, String raw, String[] cooked); -} diff --git a/service-t/src/com/android/server/NativeDaemonConnector.java b/service-t/src/com/android/server/NativeDaemonConnector.java deleted file mode 100644 index ec8d7798e1..0000000000 --- a/service-t/src/com/android/server/NativeDaemonConnector.java +++ /dev/null @@ -1,704 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * 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.android.server; - -import android.net.LocalSocket; -import android.net.LocalSocketAddress; -import android.os.Build; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.os.PowerManager; -import android.os.SystemClock; -import android.util.LocalLog; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.Objects; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Generic connector class for interfacing with a native daemon which uses the - * {@code libsysutils} FrameworkListener protocol. - */ -final class NativeDaemonConnector implements Runnable, Handler.Callback { - private final static boolean VDBG = false; - - private final String TAG; - - private String mSocket; - private OutputStream mOutputStream; - private LocalLog mLocalLog; - - private volatile boolean mDebug = false; - private volatile Object mWarnIfHeld; - - private final ResponseQueue mResponseQueue; - - private final PowerManager.WakeLock mWakeLock; - - private final Looper mLooper; - - private INativeDaemonConnectorCallbacks mCallbacks; - private Handler mCallbackHandler; - - private AtomicInteger mSequenceNumber; - - private static final long DEFAULT_TIMEOUT = 1 * 60 * 1000; /* 1 minute */ - private static final long WARN_EXECUTE_DELAY_MS = 500; /* .5 sec */ - - /** Lock held whenever communicating with native daemon. */ - private final Object mDaemonLock = new Object(); - - private final int BUFFER_SIZE = 4096; - - NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket, - int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl) { - mCallbacks = callbacks; - mSocket = socket; - mResponseQueue = new ResponseQueue(responseQueueSize); - mWakeLock = wl; - if (mWakeLock != null) { - mWakeLock.setReferenceCounted(true); - } - mSequenceNumber = new AtomicInteger(0); - TAG = logTag != null ? logTag : "NativeDaemonConnector"; - mLocalLog = new LocalLog(maxLogSize); - final HandlerThread thread = new HandlerThread(TAG); - thread.start(); - mLooper = thread.getLooper(); - } - - /** - * Enable Set debugging mode, which causes messages to also be written to both - * {@link Log} in addition to internal log. - */ - public void setDebug(boolean debug) { - mDebug = debug; - } - - /** - * Like SystemClock.uptimeMillis, except truncated to an int so it will fit in a message arg. - * Inaccurate across 49.7 days of uptime, but only used for debugging. - */ - private int uptimeMillisInt() { - return (int) SystemClock.uptimeMillis() & Integer.MAX_VALUE; - } - - /** - * Yell loudly if someone tries making future {@link #execute(Command)} - * calls while holding a lock on the given object. - */ - public void setWarnIfHeld(Object warnIfHeld) { - if (mWarnIfHeld != null) { - throw new IllegalStateException("warnIfHeld is already set."); - } - mWarnIfHeld = Objects.requireNonNull(warnIfHeld); - } - - @Override - public void run() { - mCallbackHandler = new Handler(mLooper, this); - - while (true) { - try { - listenToSocket(); - } catch (Exception e) { - loge("Error in NativeDaemonConnector: " + e); - SystemClock.sleep(5000); - } - } - } - - @Override - public boolean handleMessage(Message msg) { - final String event = (String) msg.obj; - final int start = uptimeMillisInt(); - final int sent = msg.arg1; - try { - if (!mCallbacks.onEvent(msg.what, event, NativeDaemonEvent.unescapeArgs(event))) { - log(String.format("Unhandled event '%s'", event)); - } - } catch (Exception e) { - loge("Error handling '" + event + "': " + e); - } finally { - if (mCallbacks.onCheckHoldWakeLock(msg.what) && mWakeLock != null) { - mWakeLock.release(); - } - final int end = uptimeMillisInt(); - if (start > sent && start - sent > WARN_EXECUTE_DELAY_MS) { - loge(String.format("NDC event {%s} processed too late: %dms", event, start - sent)); - } - if (end > start && end - start > WARN_EXECUTE_DELAY_MS) { - loge(String.format("NDC event {%s} took too long: %dms", event, end - start)); - } - } - return true; - } - - private LocalSocketAddress determineSocketAddress() { - // If we're testing, set up a socket in a namespace that's accessible to test code. - // In order to ensure that unprivileged apps aren't able to impersonate native daemons on - // production devices, even if said native daemons ill-advisedly pick a socket name that - // starts with __test__, only allow this on debug builds. - if (mSocket.startsWith("__test__") && Build.isDebuggable()) { - return new LocalSocketAddress(mSocket); - } else { - return new LocalSocketAddress(mSocket, LocalSocketAddress.Namespace.RESERVED); - } - } - - private void listenToSocket() throws IOException { - LocalSocket socket = null; - - try { - socket = new LocalSocket(); - LocalSocketAddress address = determineSocketAddress(); - - socket.connect(address); - - InputStream inputStream = socket.getInputStream(); - synchronized (mDaemonLock) { - mOutputStream = socket.getOutputStream(); - } - - mCallbacks.onDaemonConnected(); - - FileDescriptor[] fdList = null; - byte[] buffer = new byte[BUFFER_SIZE]; - int start = 0; - - while (true) { - int count = inputStream.read(buffer, start, BUFFER_SIZE - start); - if (count < 0) { - loge("got " + count + " reading with start = " + start); - break; - } - fdList = socket.getAncillaryFileDescriptors(); - - // Add our starting point to the count and reset the start. - count += start; - start = 0; - - for (int i = 0; i < count; i++) { - if (buffer[i] == 0) { - // Note - do not log this raw message since it may contain - // sensitive data - final String rawEvent = new String( - buffer, start, i - start, StandardCharsets.UTF_8); - - boolean releaseWl = false; - try { - final NativeDaemonEvent event = - NativeDaemonEvent.parseRawEvent(rawEvent, fdList); - - log("RCV <- {" + event + "}"); - - if (event.isClassUnsolicited()) { - // TODO: migrate to sending NativeDaemonEvent instances - if (mCallbacks.onCheckHoldWakeLock(event.getCode()) - && mWakeLock != null) { - mWakeLock.acquire(); - releaseWl = true; - } - Message msg = mCallbackHandler.obtainMessage( - event.getCode(), uptimeMillisInt(), 0, event.getRawEvent()); - if (mCallbackHandler.sendMessage(msg)) { - releaseWl = false; - } - } else { - mResponseQueue.add(event.getCmdNumber(), event); - } - } catch (IllegalArgumentException e) { - log("Problem parsing message " + e); - } finally { - if (releaseWl) { - mWakeLock.release(); - } - } - - start = i + 1; - } - } - - if (start == 0) { - log("RCV incomplete"); - } - - // We should end at the amount we read. If not, compact then - // buffer and read again. - if (start != count) { - final int remaining = BUFFER_SIZE - start; - System.arraycopy(buffer, start, buffer, 0, remaining); - start = remaining; - } else { - start = 0; - } - } - } catch (IOException ex) { - loge("Communications error: " + ex); - throw ex; - } finally { - synchronized (mDaemonLock) { - if (mOutputStream != null) { - try { - loge("closing stream for " + mSocket); - mOutputStream.close(); - } catch (IOException e) { - loge("Failed closing output stream: " + e); - } - mOutputStream = null; - } - } - - try { - if (socket != null) { - socket.close(); - } - } catch (IOException ex) { - loge("Failed closing socket: " + ex); - } - } - } - - /** - * Wrapper around argument that indicates it's sensitive and shouldn't be - * logged. - */ - public static class SensitiveArg { - private final Object mArg; - - public SensitiveArg(Object arg) { - mArg = arg; - } - - @Override - public String toString() { - return String.valueOf(mArg); - } - } - - /** - * Make command for daemon, escaping arguments as needed. - */ - @VisibleForTesting - static void makeCommand(StringBuilder rawBuilder, StringBuilder logBuilder, int sequenceNumber, - String cmd, Object... args) { - if (cmd.indexOf('\0') >= 0) { - throw new IllegalArgumentException("Unexpected command: " + cmd); - } - if (cmd.indexOf(' ') >= 0) { - throw new IllegalArgumentException("Arguments must be separate from command"); - } - - rawBuilder.append(sequenceNumber).append(' ').append(cmd); - logBuilder.append(sequenceNumber).append(' ').append(cmd); - for (Object arg : args) { - final String argString = String.valueOf(arg); - if (argString.indexOf('\0') >= 0) { - throw new IllegalArgumentException("Unexpected argument: " + arg); - } - - rawBuilder.append(' '); - logBuilder.append(' '); - - appendEscaped(rawBuilder, argString); - if (arg instanceof SensitiveArg) { - logBuilder.append("[scrubbed]"); - } else { - appendEscaped(logBuilder, argString); - } - } - - rawBuilder.append('\0'); - } - - /** - * Method that waits until all asychronous notifications sent by the native daemon have - * been processed. This method must not be called on the notification thread or an - * exception will be thrown. - */ - public void waitForCallbacks() { - if (Thread.currentThread() == mLooper.getThread()) { - throw new IllegalStateException("Must not call this method on callback thread"); - } - - final CountDownLatch latch = new CountDownLatch(1); - mCallbackHandler.post(new Runnable() { - @Override - public void run() { - latch.countDown(); - } - }); - try { - latch.await(); - } catch (InterruptedException e) { - Log.wtf(TAG, "Interrupted while waiting for unsolicited response handling", e); - } - } - - /** - * 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(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. Any arguments must be separated from base command so they can - * be properly escaped. - * - * @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 { - return execute(DEFAULT_TIMEOUT, cmd, args); - } - - public NativeDaemonEvent execute(long timeoutMs, String cmd, Object... args) - throws NativeDaemonConnectorException { - final NativeDaemonEvent[] events = executeForList(timeoutMs, 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. Any arguments must be separated from base - * command so they can be properly escaped. - * - * @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 { - return executeForList(DEFAULT_TIMEOUT, cmd, args); - } - - /** - * Issue the given command to the native daemon and return any {@linke - * NativeDaemonEvent@isClassContinue()} responses, including the final - * terminal response. Note that the timeout does not count time in deep - * sleep. Any arguments must be separated from base command so they can be - * properly escaped. - * - * @throws NativeDaemonConnectorException when problem communicating with - * native daemon, or if the response matches - * {@link NativeDaemonEvent#isClassClientError()} or - * {@link NativeDaemonEvent#isClassServerError()}. - */ - public NativeDaemonEvent[] executeForList(long timeoutMs, String cmd, Object... args) - throws NativeDaemonConnectorException { - if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) { - Log.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x" - + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable()); - } - - final long startTime = SystemClock.elapsedRealtime(); - - final ArrayList<NativeDaemonEvent> events = new ArrayList<>(); - - final StringBuilder rawBuilder = new StringBuilder(); - final StringBuilder logBuilder = new StringBuilder(); - final int sequenceNumber = mSequenceNumber.incrementAndGet(); - - makeCommand(rawBuilder, logBuilder, sequenceNumber, cmd, args); - - final String rawCmd = rawBuilder.toString(); - final String logCmd = logBuilder.toString(); - - log("SND -> {" + logCmd + "}"); - - synchronized (mDaemonLock) { - if (mOutputStream == null) { - throw new NativeDaemonConnectorException("missing output stream"); - } else { - try { - mOutputStream.write(rawCmd.getBytes(StandardCharsets.UTF_8)); - } catch (IOException e) { - throw new NativeDaemonConnectorException("problem sending command", e); - } - } - } - - NativeDaemonEvent event = null; - do { - event = mResponseQueue.remove(sequenceNumber, timeoutMs, logCmd); - if (event == null) { - loge("timed-out waiting for response to " + logCmd); - throw new NativeDaemonTimeoutException(logCmd, event); - } - if (VDBG) log("RMV <- {" + event + "}"); - events.add(event); - } while (event.isClassContinue()); - - final long endTime = SystemClock.elapsedRealtime(); - if (endTime - startTime > WARN_EXECUTE_DELAY_MS) { - loge("NDC Command {" + logCmd + "} took too long (" + (endTime - startTime) + "ms)"); - } - - if (event.isClassClientError()) { - throw new NativeDaemonArgumentException(logCmd, event); - } - if (event.isClassServerError()) { - throw new NativeDaemonFailureException(logCmd, event); - } - - return events.toArray(new NativeDaemonEvent[events.size()]); - } - - /** - * Append the given argument to {@link StringBuilder}, escaping as needed, - * and surrounding with quotes when it contains spaces. - */ - @VisibleForTesting - static void appendEscaped(StringBuilder builder, String arg) { - final boolean hasSpaces = arg.indexOf(' ') >= 0; - if (hasSpaces) { - builder.append('"'); - } - - final int length = arg.length(); - for (int i = 0; i < length; i++) { - final char c = arg.charAt(i); - - if (c == '"') { - builder.append("\\\""); - } else if (c == '\\') { - builder.append("\\\\"); - } else { - builder.append(c); - } - } - - if (hasSpaces) { - builder.append('"'); - } - } - - private static class NativeDaemonArgumentException extends NativeDaemonConnectorException { - public NativeDaemonArgumentException(String command, NativeDaemonEvent event) { - super(command, event); - } - - @Override - public IllegalArgumentException rethrowAsParcelableException() { - throw new IllegalArgumentException(getMessage(), this); - } - } - - private static class NativeDaemonFailureException extends NativeDaemonConnectorException { - public NativeDaemonFailureException(String command, NativeDaemonEvent event) { - super(command, event); - } - } - - /** - * Command builder that handles argument list building. Any arguments must - * be separated from base command so they can be properly escaped. - */ - public static class Command { - private String mCmd; - private ArrayList<Object> mArguments = new ArrayList<>(); - - public Command(String cmd, Object... args) { - mCmd = cmd; - for (Object arg : args) { - appendArg(arg); - } - } - - public Command appendArg(Object arg) { - mArguments.add(arg); - return this; - } - } - - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - mLocalLog.dump(fd, pw, args); - pw.println(); - mResponseQueue.dump(fd, pw, args); - } - - private void log(String logstring) { - if (mDebug) Log.d(TAG, logstring); - mLocalLog.log(logstring); - } - - private void loge(String logstring) { - Log.e(TAG, logstring); - mLocalLog.log(logstring); - } - - private static class ResponseQueue { - - private static class PendingCmd { - public final int cmdNum; - public final String logCmd; - - public BlockingQueue<NativeDaemonEvent> responses = - new ArrayBlockingQueue<NativeDaemonEvent>(10); - - // The availableResponseCount member is used to track when we can remove this - // instance from the ResponseQueue. - // This is used under the protection of a sync of the mPendingCmds object. - // A positive value means we've had more writers retreive this object while - // a negative value means we've had more readers. When we've had an equal number - // (it goes to zero) we can remove this object from the mPendingCmds list. - // Note that we may have more responses for this command (and more readers - // coming), but that would result in a new PendingCmd instance being created - // and added with the same cmdNum. - // Also note that when this goes to zero it just means a parity of readers and - // writers have retrieved this object - not that they are done using it. The - // responses queue may well have more responses yet to be read or may get more - // responses added to it. But all those readers/writers have retreived and - // hold references to this instance already so it can be removed from - // mPendingCmds queue. - public int availableResponseCount; - - public PendingCmd(int cmdNum, String logCmd) { - this.cmdNum = cmdNum; - this.logCmd = logCmd; - } - } - - private final LinkedList<PendingCmd> mPendingCmds; - private int mMaxCount; - - ResponseQueue(int maxCount) { - mPendingCmds = new LinkedList<PendingCmd>(); - mMaxCount = maxCount; - } - - public void add(int cmdNum, NativeDaemonEvent response) { - PendingCmd found = null; - synchronized (mPendingCmds) { - for (PendingCmd pendingCmd : mPendingCmds) { - if (pendingCmd.cmdNum == cmdNum) { - found = pendingCmd; - break; - } - } - if (found == null) { - // didn't find it - make sure our queue isn't too big before adding - while (mPendingCmds.size() >= mMaxCount) { - Log.e("NativeDaemonConnector.ResponseQueue", - "more buffered than allowed: " + mPendingCmds.size() + - " >= " + mMaxCount); - // let any waiter timeout waiting for this - PendingCmd pendingCmd = mPendingCmds.remove(); - Log.e("NativeDaemonConnector.ResponseQueue", - "Removing request: " + pendingCmd.logCmd + " (" + - pendingCmd.cmdNum + ")"); - } - found = new PendingCmd(cmdNum, null); - mPendingCmds.add(found); - } - found.availableResponseCount++; - // if a matching remove call has already retrieved this we can remove this - // instance from our list - if (found.availableResponseCount == 0) mPendingCmds.remove(found); - } - try { - found.responses.put(response); - } catch (InterruptedException e) { } - } - - // note that the timeout does not count time in deep sleep. If you don't want - // the device to sleep, hold a wakelock - public NativeDaemonEvent remove(int cmdNum, long timeoutMs, String logCmd) { - PendingCmd found = null; - synchronized (mPendingCmds) { - for (PendingCmd pendingCmd : mPendingCmds) { - if (pendingCmd.cmdNum == cmdNum) { - found = pendingCmd; - break; - } - } - if (found == null) { - found = new PendingCmd(cmdNum, logCmd); - mPendingCmds.add(found); - } - found.availableResponseCount--; - // if a matching add call has already retrieved this we can remove this - // instance from our list - if (found.availableResponseCount == 0) mPendingCmds.remove(found); - } - NativeDaemonEvent result = null; - try { - result = found.responses.poll(timeoutMs, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) {} - if (result == null) { - Log.e("NativeDaemonConnector.ResponseQueue", "Timeout waiting for response"); - } - return result; - } - - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("Pending requests:"); - synchronized (mPendingCmds) { - for (PendingCmd pendingCmd : mPendingCmds) { - pw.println(" Cmd " + pendingCmd.cmdNum + " - " + pendingCmd.logCmd); - } - } - } - } -} diff --git a/service-t/src/com/android/server/NativeDaemonConnectorException.java b/service-t/src/com/android/server/NativeDaemonConnectorException.java deleted file mode 100644 index 4d8881c683..0000000000 --- a/service-t/src/com/android/server/NativeDaemonConnectorException.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * 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.android.server; - -import android.os.Parcel; - -/** - * An exception that indicates there was an error with a - * {@link NativeDaemonConnector} operation. - */ -public class NativeDaemonConnectorException extends Exception { - private String mCmd; - private NativeDaemonEvent mEvent; - - public NativeDaemonConnectorException(String detailMessage) { - super(detailMessage); - } - - public NativeDaemonConnectorException(String detailMessage, Throwable throwable) { - super(detailMessage, throwable); - } - - public NativeDaemonConnectorException(String cmd, NativeDaemonEvent event) { - super("command '" + cmd + "' failed with '" + event + "'"); - mCmd = cmd; - mEvent = event; - } - - public int getCode() { - return mEvent != null ? mEvent.getCode() : -1; - } - - public String getCmd() { - return mCmd; - } - - /** - * Rethrow as a {@link RuntimeException} subclass that is handled by - * {@link Parcel#writeException(Exception)}. - */ - public IllegalArgumentException rethrowAsParcelableException() { - throw new IllegalStateException(getMessage(), this); - } -} diff --git a/service-t/src/com/android/server/NativeDaemonEvent.java b/service-t/src/com/android/server/NativeDaemonEvent.java deleted file mode 100644 index 5683694346..0000000000 --- a/service-t/src/com/android/server/NativeDaemonEvent.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * 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.android.server; - -import android.util.Log; - -import java.io.FileDescriptor; -import java.util.ArrayList; - -/** - * Parsed event from native side of {@link NativeDaemonConnector}. - */ -public class NativeDaemonEvent { - - // TODO: keep class ranges in sync with ResponseCode.h - // TODO: swap client and server error ranges to roughly mirror HTTP spec - - private final int mCmdNumber; - private final int mCode; - private final String mMessage; - private final String mRawEvent; - private final String mLogMessage; - private String[] mParsed; - private FileDescriptor[] mFdList; - - private NativeDaemonEvent(int cmdNumber, int code, String message, - String rawEvent, String logMessage, FileDescriptor[] fdList) { - mCmdNumber = cmdNumber; - mCode = code; - mMessage = message; - mRawEvent = rawEvent; - mLogMessage = logMessage; - mParsed = null; - mFdList = fdList; - } - - static public final String SENSITIVE_MARKER = "{{sensitive}}"; - - public int getCmdNumber() { - return mCmdNumber; - } - - public int getCode() { - return mCode; - } - - public String getMessage() { - return mMessage; - } - - public FileDescriptor[] getFileDescriptors() { - return mFdList; - } - - @Deprecated - public String getRawEvent() { - return mRawEvent; - } - - @Override - public String toString() { - return mLogMessage; - } - - /** - * Test if event represents a partial response which is continued in - * additional subsequent events. - */ - public boolean isClassContinue() { - return mCode >= 100 && mCode < 200; - } - - /** - * Test if event represents a command success. - */ - public boolean isClassOk() { - return mCode >= 200 && mCode < 300; - } - - /** - * Test if event represents a remote native daemon error. - */ - public boolean isClassServerError() { - return mCode >= 400 && mCode < 500; - } - - /** - * Test if event represents a command syntax or argument error. - */ - public boolean isClassClientError() { - return mCode >= 500 && mCode < 600; - } - - /** - * Test if event represents an unsolicited event from native daemon. - */ - public boolean isClassUnsolicited() { - return isClassUnsolicited(mCode); - } - - private static boolean isClassUnsolicited(int code) { - return code >= 600 && code < 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. - * - * @throws IllegalArgumentException when line doesn't match format expected - * from native side. - */ - public static NativeDaemonEvent parseRawEvent(String rawEvent, FileDescriptor[] fdList) { - final String[] parsed = rawEvent.split(" "); - if (parsed.length < 2) { - throw new IllegalArgumentException("Insufficient arguments"); - } - - int skiplength = 0; - - final int code; - try { - code = Integer.parseInt(parsed[0]); - skiplength = parsed[0].length() + 1; - } catch (NumberFormatException e) { - throw new IllegalArgumentException("problem parsing code", e); - } - - int cmdNumber = -1; - if (isClassUnsolicited(code) == false) { - if (parsed.length < 3) { - throw new IllegalArgumentException("Insufficient arguemnts"); - } - try { - cmdNumber = Integer.parseInt(parsed[1]); - skiplength += parsed[1].length() + 1; - } catch (NumberFormatException e) { - throw new IllegalArgumentException("problem parsing cmdNumber", e); - } - } - - String logMessage = rawEvent; - if (parsed.length > 2 && parsed[2].equals(SENSITIVE_MARKER)) { - skiplength += parsed[2].length() + 1; - logMessage = parsed[0] + " " + parsed[1] + " {}"; - } - - final String message = rawEvent.substring(skiplength); - - return new NativeDaemonEvent(cmdNumber, code, message, rawEvent, logMessage, fdList); - } - - /** - * 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 = new ArrayList<>(); - for (NativeDaemonEvent event : events) { - if (event.getCode() == matchCode) { - result.add(event.getMessage()); - } - } - 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) Log.e(LOGTAG, "parsing '" + rawEvent + "'"); - if (rawEvent.charAt(current) == '\"') { - quoted = true; - current++; - } - while (current < length) { - // find the end of the word - char terminator = quoted ? '\"' : ' '; - wordEnd = current; - while (wordEnd < length && rawEvent.charAt(wordEnd) != terminator) { - if (rawEvent.charAt(wordEnd) == '\\') { - // skip the escaped char - ++wordEnd; - } - ++wordEnd; - } - if (wordEnd > length) 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 = word.replace("\\\\", "\\"); - word = word.replace("\\\"", "\""); - - if (DEBUG_ROUTINE) Log.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) { - Log.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) { - Log.e(LOGTAG, "next loop - current=" + current - + ", length=" + length + ", quoted=" + quoted); - } - } - return parsed.toArray(new String[parsed.size()]); - } -} diff --git a/service-t/src/com/android/server/NativeDaemonTimeoutException.java b/service-t/src/com/android/server/NativeDaemonTimeoutException.java deleted file mode 100644 index 658f7d6264..0000000000 --- a/service-t/src/com/android/server/NativeDaemonTimeoutException.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * 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.android.server; - -/** - * An exception that indicates there was a timeout with a - * {@link NativeDaemonConnector} operation. - */ -public class NativeDaemonTimeoutException extends NativeDaemonConnectorException { - public NativeDaemonTimeoutException(String command, NativeDaemonEvent event) { - super(command, event); - } -} - diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp index 4c63cba455..545f7b92e7 100644 --- a/tests/unit/Android.bp +++ b/tests/unit/Android.bp @@ -76,7 +76,6 @@ filegroup { "java/com/android/server/IpSecServiceParameterizedTest.java", "java/com/android/server/IpSecServiceRefcountedResourceTest.java", "java/com/android/server/IpSecServiceTest.java", - "java/com/android/server/NativeDaemonConnectorTest.java", "java/com/android/server/NetworkManagementServiceTest.java", "java/com/android/server/NsdServiceTest.java", "java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java", diff --git a/tests/unit/java/com/android/server/NativeDaemonConnectorTest.java b/tests/unit/java/com/android/server/NativeDaemonConnectorTest.java deleted file mode 100644 index e2253a2151..0000000000 --- a/tests/unit/java/com/android/server/NativeDaemonConnectorTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * 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.android.server; - -import static com.android.server.NativeDaemonConnector.appendEscaped; -import static com.android.server.NativeDaemonConnector.makeCommand; - -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.MediumTest; - -import com.android.server.NativeDaemonConnector.SensitiveArg; - -/** - * Tests for {@link NativeDaemonConnector}. - */ -@MediumTest -public class NativeDaemonConnectorTest extends AndroidTestCase { - private static final String TAG = "NativeDaemonConnectorTest"; - - public void testArgumentNormal() throws Exception { - final StringBuilder builder = new StringBuilder(); - - builder.setLength(0); - appendEscaped(builder, ""); - assertEquals("", builder.toString()); - - builder.setLength(0); - appendEscaped(builder, "foo"); - assertEquals("foo", builder.toString()); - - builder.setLength(0); - appendEscaped(builder, "foo\"bar"); - assertEquals("foo\\\"bar", builder.toString()); - - builder.setLength(0); - appendEscaped(builder, "foo\\bar\\\"baz"); - assertEquals("foo\\\\bar\\\\\\\"baz", builder.toString()); - } - - public void testArgumentWithSpaces() throws Exception { - final StringBuilder builder = new StringBuilder(); - - builder.setLength(0); - appendEscaped(builder, "foo bar"); - assertEquals("\"foo bar\"", builder.toString()); - - builder.setLength(0); - appendEscaped(builder, "foo\"bar\\baz foo"); - assertEquals("\"foo\\\"bar\\\\baz foo\"", builder.toString()); - } - - public void testArgumentWithUtf() throws Exception { - final StringBuilder builder = new StringBuilder(); - - builder.setLength(0); - appendEscaped(builder, "caf\u00E9 c\u00F6ffee"); - assertEquals("\"caf\u00E9 c\u00F6ffee\"", builder.toString()); - } - - public void testSensitiveArgs() throws Exception { - final StringBuilder rawBuilder = new StringBuilder(); - final StringBuilder logBuilder = new StringBuilder(); - - rawBuilder.setLength(0); - logBuilder.setLength(0); - makeCommand(rawBuilder, logBuilder, 1, "foo", "bar", "baz"); - assertEquals("1 foo bar baz\0", rawBuilder.toString()); - assertEquals("1 foo bar baz", logBuilder.toString()); - - rawBuilder.setLength(0); - logBuilder.setLength(0); - makeCommand(rawBuilder, logBuilder, 1, "foo", new SensitiveArg("bar"), "baz"); - assertEquals("1 foo bar baz\0", rawBuilder.toString()); - assertEquals("1 foo [scrubbed] baz", logBuilder.toString()); - - rawBuilder.setLength(0); - logBuilder.setLength(0); - makeCommand(rawBuilder, logBuilder, 1, "foo", new SensitiveArg("foo bar"), "baz baz", - new SensitiveArg("wat")); - assertEquals("1 foo \"foo bar\" \"baz baz\" wat\0", rawBuilder.toString()); - assertEquals("1 foo [scrubbed] \"baz baz\" [scrubbed]", logBuilder.toString()); - } -} |