Merge "Implemented a PriorityDump helper."
This commit is contained in:
committed by
Android (Google) Code Review
commit
f4ec97be71
179
services/core/java/com/android/server/utils/PriorityDump.java
Normal file
179
services/core/java/com/android/server/utils/PriorityDump.java
Normal file
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* Copyright (c) 2016, 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.utils;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Helper for {@link android.os.Binder#dump(java.io.FileDescriptor, String[])} that supports the
|
||||
* {@link #PRIORITY_ARG} argument.
|
||||
* <p>
|
||||
* Typical usage:
|
||||
*
|
||||
* <pre><code>
|
||||
public class SpringfieldNuclearPowerPlant extends Binder {
|
||||
|
||||
private final PriorityDump.PriorityDumper mPriorityDumper = new PriorityDump.PriorityDumper() {
|
||||
|
||||
@Override
|
||||
public void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
pw.println("Donuts in the box: 1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
pw.println("Nuclear reactor status: DANGER - MELTDOWN IMMINENT");
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
PriorityDump.dump(mPriorityDumper, fd, pw, args);
|
||||
}
|
||||
}
|
||||
|
||||
* </code></pre>
|
||||
*
|
||||
* <strong>Disclaimer</strong>: a real-life service should prioritize core status over donuts :-)
|
||||
*
|
||||
* <p>Then to invoke it:
|
||||
*
|
||||
* <pre><code>
|
||||
*
|
||||
$ adb shell dumpsys snpp
|
||||
Donuts in the box: 1
|
||||
Nuclear reactor status: DANGER - MELTDOWN IMMINENT
|
||||
|
||||
$ adb shell dumpsys snpp --dump_priority CRITICAL
|
||||
Donuts in the box: 1
|
||||
|
||||
$ adb shell dumpsys snpp --dump_priority NORMAL
|
||||
Nuclear reactor status: DANGER - MELTDOWN IMMINENT
|
||||
|
||||
* </code></pre>
|
||||
*
|
||||
*
|
||||
*
|
||||
* <p>To run the unit tests:
|
||||
* <pre><code>
|
||||
*
|
||||
mmm -j32 frameworks/base/services/tests/servicestests/ && \
|
||||
adb install -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk && \
|
||||
adb shell am instrument -e class "com.android.server.utils.PriorityDumpTest" \
|
||||
-w "com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner"
|
||||
|
||||
* </code></pre>
|
||||
*
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class PriorityDump {
|
||||
|
||||
public static final String PRIORITY_ARG = "--dump_priority";
|
||||
|
||||
private PriorityDump() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses {@code} and call the proper {@link PriorityDumper} method when the first argument is
|
||||
* {@code --dump_priority}, stripping the priority and its type.
|
||||
* <p>
|
||||
* For example, if called as {@code --dump_priority HIGH arg1 arg2 arg3}, it will call
|
||||
* <code>dumper.dumpHigh(fd, pw, {"arg1", "arg2", "arg3"}) </code>
|
||||
* <p>
|
||||
* If the {@code --dump_priority} is not set, it calls
|
||||
* {@link PriorityDumper#dump(FileDescriptor, PrintWriter, String[])} passing the whole
|
||||
* {@code args} instead.
|
||||
*/
|
||||
public static void dump(PriorityDumper dumper, FileDescriptor fd, PrintWriter pw,
|
||||
String[] args) {
|
||||
if (args != null && args.length >= 2 && args[0].equals(PRIORITY_ARG)) {
|
||||
final String priority = args[1];
|
||||
switch (priority) {
|
||||
case "CRITICAL": {
|
||||
dumper.dumpCritical(fd, pw, getStrippedArgs(args));
|
||||
return;
|
||||
}
|
||||
case "HIGH": {
|
||||
dumper.dumpHigh(fd, pw, getStrippedArgs(args));
|
||||
return;
|
||||
}
|
||||
case "NORMAL": {
|
||||
dumper.dumpNormal(fd, pw, getStrippedArgs(args));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
dumper.dump(fd, pw, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array without the {@code --dump_priority PRIORITY} prefix.
|
||||
*/
|
||||
private static String[] getStrippedArgs(String[] args) {
|
||||
final String[] stripped = new String[args.length - 2];
|
||||
System.arraycopy(args, 2, stripped, 0, stripped.length);
|
||||
return stripped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for {@link android.os.Binder#dump(java.io.FileDescriptor, String[])} that supports the
|
||||
* {@link #PRIORITY_ARG} argument.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static interface PriorityDumper {
|
||||
|
||||
/**
|
||||
* Dumps only the critical section.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
default void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps only the high-priority section.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
default void dumpHigh(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps only the normal section.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
default void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps all sections.
|
||||
* <p>
|
||||
* This method is called when
|
||||
* {@link PriorityDump#dump(PriorityDumper, FileDescriptor, PrintWriter, String[])} is
|
||||
* called without priority arguments. By default, it calls the 3 {@code dumpTYPE} methods,
|
||||
* so sub-classes just need to implement the priority types they support.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
default void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
dumpCritical(fd, pw, args);
|
||||
dumpHigh(fd, pw, args);
|
||||
dumpNormal(fd, pw, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* Copyright (c) 2016, 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.utils;
|
||||
|
||||
import static com.android.server.utils.PriorityDump.dump;
|
||||
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Matchers.same;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import com.android.server.utils.PriorityDump.PriorityDumper;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
@SmallTest
|
||||
@Presubmit
|
||||
@RunWith(JUnit4.class)
|
||||
public class PriorityDumpTest {
|
||||
|
||||
private static final String[] EMPTY_ARGS = {};
|
||||
|
||||
@Mock
|
||||
private PriorityDumper mDumper;
|
||||
@Mock
|
||||
private PrintWriter mPw;
|
||||
|
||||
private final FileDescriptor mFd = FileDescriptor.err;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullArgs() {
|
||||
dump(mDumper, mFd, mPw, null);
|
||||
verify(mDumper).dump(same(mFd), same(mPw), eq(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoArgs() {
|
||||
dump(mDumper, mFd, mPw, EMPTY_ARGS);
|
||||
verify(mDumper).dump(same(mFd), same(mPw), same(EMPTY_ARGS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonPriorityArgs() {
|
||||
final String[] args = {
|
||||
"--dumb_priority"
|
||||
};
|
||||
dump(mDumper, mFd, mPw, args);
|
||||
verify(mDumper).dump(same(mFd), same(mPw), same(args));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingPriority() {
|
||||
final String[] args = {
|
||||
"--dump_priority"
|
||||
};
|
||||
dump(mDumper, mFd, mPw, args);
|
||||
verify(mDumper).dump(same(mFd), same(mPw), same(args));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidPriorityNoExtraArgs() {
|
||||
final String[] args = {
|
||||
"--dump_priority", "SUPER_HIGH"
|
||||
};
|
||||
dump(mDumper, mFd, mPw, args);
|
||||
verify(mDumper).dump(same(mFd), same(mPw), same(args));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidPriorityExtraArgs() {
|
||||
final String[] args = {
|
||||
"--dump_priority", "SUPER_HIGH", "--high", "--five"
|
||||
};
|
||||
dump(mDumper, mFd, mPw, args);
|
||||
verify(mDumper).dump(same(mFd), same(mPw), same(args));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoPriorityCallsAllMethods() {
|
||||
final String[] args = {
|
||||
"1", "2", "3"
|
||||
};
|
||||
|
||||
// Cannot use mDumper here because it would mock the dump() call.
|
||||
final FakeDumper fakeDumper = new FakeDumper();
|
||||
|
||||
dump(fakeDumper, mFd, mPw, args);
|
||||
|
||||
assertSame(mFd, fakeDumper.criticalFd);
|
||||
assertSame(mPw, fakeDumper.criticalPw);
|
||||
assertSame(args, fakeDumper.criticalArgs);
|
||||
assertSame(mFd, fakeDumper.highFd);
|
||||
assertSame(mPw, fakeDumper.highPw);
|
||||
assertSame(args, fakeDumper.highArgs);
|
||||
assertSame(mFd, fakeDumper.normalFd);
|
||||
assertSame(mPw, fakeDumper.normalPw);
|
||||
assertSame(args, fakeDumper.normalArgs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCriticalNoExtraArgs() {
|
||||
dump(mDumper, mFd, mPw, new String[] {
|
||||
"--dump_priority", "CRITICAL"
|
||||
});
|
||||
verify(mDumper).dumpCritical(same(mFd), same(mPw), eq(EMPTY_ARGS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCriticalExtraArgs() {
|
||||
dump(mDumper, mFd, mPw, new String[] {
|
||||
"--dump_priority", "CRITICAL", "--high", "--five"
|
||||
});
|
||||
verify(mDumper).dumpCritical(same(mFd), same(mPw), eq(new String[] {
|
||||
"--high", "--five"
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHighNoExtraArgs() {
|
||||
dump(mDumper, mFd, mPw, new String[] {
|
||||
"--dump_priority", "HIGH"
|
||||
});
|
||||
verify(mDumper).dumpHigh(same(mFd), same(mPw), eq(EMPTY_ARGS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHighExtraArgs() {
|
||||
dump(mDumper, mFd, mPw, new String[] {
|
||||
"--dump_priority", "HIGH", "--high", "--five"
|
||||
});
|
||||
verify(mDumper).dumpHigh(same(mFd), same(mPw), eq(new String[] {
|
||||
"--high", "--five"
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalNoExtraArgs() {
|
||||
dump(mDumper, mFd, mPw, new String[] {
|
||||
"--dump_priority", "NORMAL"
|
||||
});
|
||||
verify(mDumper).dumpNormal(same(mFd), same(mPw), eq(EMPTY_ARGS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalExtraArgs() {
|
||||
dump(mDumper, mFd, mPw, new String[] {
|
||||
"--dump_priority", "NORMAL", "--high", "--five"
|
||||
});
|
||||
verify(mDumper).dumpNormal(same(mFd), same(mPw), eq(new String[] {
|
||||
"--high", "--five"
|
||||
}));
|
||||
}
|
||||
|
||||
private final class FakeDumper implements PriorityDumper {
|
||||
|
||||
String[] criticalArgs, highArgs, normalArgs;
|
||||
FileDescriptor criticalFd, highFd, normalFd;
|
||||
PrintWriter criticalPw, highPw, normalPw;
|
||||
|
||||
@Override
|
||||
public void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
criticalFd = fd;
|
||||
criticalPw = pw;
|
||||
criticalArgs = args;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dumpHigh(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
highFd = fd;
|
||||
highPw = pw;
|
||||
highArgs = args;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
normalFd = fd;
|
||||
normalPw = pw;
|
||||
normalArgs = args;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user