1 /** 2 * Copyright (c) 2016, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.utils; 18 19 import java.io.FileDescriptor; 20 import java.io.PrintWriter; 21 22 /** 23 * Helper for {@link android.os.Binder#dump(java.io.FileDescriptor, String[])} that supports the 24 * {@link #PRIORITY_ARG} argument. 25 * <p> 26 * Typical usage: 27 * 28 * <pre><code> 29 public class SpringfieldNuclearPowerPlant extends Binder { 30 31 private final PriorityDump.PriorityDumper mPriorityDumper = new PriorityDump.PriorityDumper() { 32 33 @Override 34 public void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args) { 35 pw.println("Donuts in the box: 1"); 36 } 37 38 @Override 39 public void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args) { 40 pw.println("Nuclear reactor status: DANGER - MELTDOWN IMMINENT"); 41 } 42 }; 43 44 @Override 45 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 46 PriorityDump.dump(mPriorityDumper, fd, pw, args); 47 } 48 } 49 50 * </code></pre> 51 * 52 * <strong>Disclaimer</strong>: a real-life service should prioritize core status over donuts :-) 53 * 54 * <p>Then to invoke it: 55 * 56 * <pre><code> 57 * 58 $ adb shell dumpsys snpp 59 Donuts in the box: 1 60 Nuclear reactor status: DANGER - MELTDOWN IMMINENT 61 62 $ adb shell dumpsys snpp --dump_priority CRITICAL 63 Donuts in the box: 1 64 65 $ adb shell dumpsys snpp --dump_priority NORMAL 66 Nuclear reactor status: DANGER - MELTDOWN IMMINENT 67 68 * </code></pre> 69 * 70 * 71 * 72 * <p>To run the unit tests: 73 * <pre><code> 74 * 75 mmm -j32 frameworks/base/services/tests/servicestests/ && \ 76 adb install -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk && \ 77 adb shell am instrument -e class "com.android.server.utils.PriorityDumpTest" \ 78 -w "com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner" 79 80 * </code></pre> 81 * 82 * 83 * @hide 84 */ 85 public final class PriorityDump { 86 87 public static final String PRIORITY_ARG = "--dump_priority"; 88 PriorityDump()89 private PriorityDump() { 90 throw new UnsupportedOperationException(); 91 } 92 93 /** 94 * Parses {@code} and call the proper {@link PriorityDumper} method when the first argument is 95 * {@code --dump_priority}, stripping the priority and its type. 96 * <p> 97 * For example, if called as {@code --dump_priority HIGH arg1 arg2 arg3}, it will call 98 * <code>dumper.dumpHigh(fd, pw, {"arg1", "arg2", "arg3"}) </code> 99 * <p> 100 * If the {@code --dump_priority} is not set, it calls 101 * {@link PriorityDumper#dump(FileDescriptor, PrintWriter, String[])} passing the whole 102 * {@code args} instead. 103 */ dump(PriorityDumper dumper, FileDescriptor fd, PrintWriter pw, String[] args)104 public static void dump(PriorityDumper dumper, FileDescriptor fd, PrintWriter pw, 105 String[] args) { 106 if (args != null && args.length >= 2 && args[0].equals(PRIORITY_ARG)) { 107 final String priority = args[1]; 108 switch (priority) { 109 case "CRITICAL": { 110 dumper.dumpCritical(fd, pw, getStrippedArgs(args)); 111 return; 112 } 113 case "HIGH": { 114 dumper.dumpHigh(fd, pw, getStrippedArgs(args)); 115 return; 116 } 117 case "NORMAL": { 118 dumper.dumpNormal(fd, pw, getStrippedArgs(args)); 119 return; 120 } 121 } 122 } 123 dumper.dump(fd, pw, args); 124 } 125 126 /** 127 * Gets an array without the {@code --dump_priority PRIORITY} prefix. 128 */ getStrippedArgs(String[] args)129 private static String[] getStrippedArgs(String[] args) { 130 final String[] stripped = new String[args.length - 2]; 131 System.arraycopy(args, 2, stripped, 0, stripped.length); 132 return stripped; 133 } 134 135 /** 136 * Helper for {@link android.os.Binder#dump(java.io.FileDescriptor, String[])} that supports the 137 * {@link #PRIORITY_ARG} argument. 138 * 139 * @hide 140 */ 141 public static interface PriorityDumper { 142 143 /** 144 * Dumps only the critical section. 145 */ 146 @SuppressWarnings("unused") dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args)147 default void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args) { 148 } 149 150 /** 151 * Dumps only the high-priority section. 152 */ 153 @SuppressWarnings("unused") dumpHigh(FileDescriptor fd, PrintWriter pw, String[] args)154 default void dumpHigh(FileDescriptor fd, PrintWriter pw, String[] args) { 155 } 156 157 /** 158 * Dumps only the normal section. 159 */ 160 @SuppressWarnings("unused") dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args)161 default void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args) { 162 } 163 164 /** 165 * Dumps all sections. 166 * <p> 167 * This method is called when 168 * {@link PriorityDump#dump(PriorityDumper, FileDescriptor, PrintWriter, String[])} is 169 * called without priority arguments. By default, it calls the 3 {@code dumpTYPE} methods, 170 * so sub-classes just need to implement the priority types they support. 171 */ 172 @SuppressWarnings("unused") dump(FileDescriptor fd, PrintWriter pw, String[] args)173 default void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 174 dumpCritical(fd, pw, args); 175 dumpHigh(fd, pw, args); 176 dumpNormal(fd, pw, args); 177 } 178 } 179 } 180