blob: d9fb9c07e993c617c21f5aa4c560792bdc7df95e [file] [log] [blame]
Felipe Lemef4006d92016-10-07 17:57:13 -07001/**
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
17package com.android.server.utils;
18
Vishnu Naire78b01a2017-10-26 10:11:54 -070019import android.annotation.IntDef;
20
Felipe Lemef4006d92016-10-07 17:57:13 -070021import java.io.FileDescriptor;
22import java.io.PrintWriter;
Vishnu Naire78b01a2017-10-26 10:11:54 -070023import java.lang.annotation.Retention;
24import java.lang.annotation.RetentionPolicy;
25import java.util.ArrayList;
26import java.util.Arrays;
27import java.util.Iterator;
Felipe Lemef4006d92016-10-07 17:57:13 -070028
29/**
30 * Helper for {@link android.os.Binder#dump(java.io.FileDescriptor, String[])} that supports the
Vishnu Naire78b01a2017-10-26 10:11:54 -070031 * {@link #PRIORITY_ARG} and {@link #PROTO_ARG} arguments.
Felipe Lemef4006d92016-10-07 17:57:13 -070032 * <p>
33 * Typical usage:
34 *
35 * <pre><code>
36public class SpringfieldNuclearPowerPlant extends Binder {
37
38 private final PriorityDump.PriorityDumper mPriorityDumper = new PriorityDump.PriorityDumper() {
39
40 @Override
Vishnu Naire78b01a2017-10-26 10:11:54 -070041 public void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) {
42 if (asProto) {
43 ProtoOutputStream proto = new ProtoOutputStream(fd);
44 proto.write(SpringfieldProto.DONUTS, 1);
45 proto.flush();
46 } else {
47 pw.println("Donuts in the box: 1");
48 }
Felipe Lemef4006d92016-10-07 17:57:13 -070049 }
50
51 @Override
52 public void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args) {
Vishnu Naire78b01a2017-10-26 10:11:54 -070053 if (asProto) {
54 ProtoOutputStream proto = new ProtoOutputStream(fd);
55 proto.write(SpringfieldProto.REACTOR_STATUS, DANGER_MELTDOWN_IMMINENT);
56 proto.flush();
57 } else {
58 pw.println("Nuclear reactor status: DANGER - MELTDOWN IMMINENT");
59 }
Felipe Lemef4006d92016-10-07 17:57:13 -070060 }
61 };
62
63 @Override
64 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
65 PriorityDump.dump(mPriorityDumper, fd, pw, args);
66 }
67}
68
69 * </code></pre>
70 *
71 * <strong>Disclaimer</strong>: a real-life service should prioritize core status over donuts :-)
72 *
73 * <p>Then to invoke it:
74 *
75 * <pre><code>
76 *
77 $ adb shell dumpsys snpp
78 Donuts in the box: 1
79 Nuclear reactor status: DANGER - MELTDOWN IMMINENT
80
Vishnu Nairf3648e02017-09-13 10:41:28 -070081 $ adb shell dumpsys snpp --dump-priority CRITICAL
Felipe Lemef4006d92016-10-07 17:57:13 -070082 Donuts in the box: 1
83
Vishnu Nairf3648e02017-09-13 10:41:28 -070084 $ adb shell dumpsys snpp --dump-priority NORMAL
Felipe Lemef4006d92016-10-07 17:57:13 -070085 Nuclear reactor status: DANGER - MELTDOWN IMMINENT
86
Vishnu Naire78b01a2017-10-26 10:11:54 -070087 $ adb shell dumpsys snpp --dump-priority CRITICAL --proto
88 //binary output
89
Felipe Lemef4006d92016-10-07 17:57:13 -070090 * </code></pre>
91 *
92 *
93 *
94 * <p>To run the unit tests:
95 * <pre><code>
96 *
Vishnu Naire3e4d252018-03-01 11:26:57 -080097 atest FrameworksServicesTests:PriorityDumpTest
Felipe Lemef4006d92016-10-07 17:57:13 -070098 * </code></pre>
99 *
100 *
101 * @hide
102 */
103public final class PriorityDump {
104
Vishnu Nairf3648e02017-09-13 10:41:28 -0700105 public static final String PRIORITY_ARG = "--dump-priority";
Vishnu Naire78b01a2017-10-26 10:11:54 -0700106 public static final String PROTO_ARG = "--proto";
Vishnu Naire3e4d252018-03-01 11:26:57 -0800107 public static final String PRIORITY_ARG_CRITICAL = "CRITICAL";
108 public static final String PRIORITY_ARG_HIGH = "HIGH";
109 public static final String PRIORITY_ARG_NORMAL = "NORMAL";
Felipe Lemef4006d92016-10-07 17:57:13 -0700110
111 private PriorityDump() {
112 throw new UnsupportedOperationException();
113 }
114
Vishnu Naire78b01a2017-10-26 10:11:54 -0700115 /** Enum to switch through supported priority types */
116 @Retention(RetentionPolicy.SOURCE)
117 @IntDef({PRIORITY_TYPE_INVALID, PRIORITY_TYPE_CRITICAL, PRIORITY_TYPE_HIGH,
118 PRIORITY_TYPE_NORMAL})
119 private @interface PriorityType { }
120 private static final int PRIORITY_TYPE_INVALID = 0;
121 private static final int PRIORITY_TYPE_CRITICAL = 1;
122 private static final int PRIORITY_TYPE_HIGH = 2;
123 private static final int PRIORITY_TYPE_NORMAL = 3;
124
Felipe Lemef4006d92016-10-07 17:57:13 -0700125 /**
Vishnu Naire78b01a2017-10-26 10:11:54 -0700126 * Parses {@code args} matching {@code --dump-priority} and/or {@code --proto}. The matching
127 * arguments are stripped.
128 * <p>
129 * If priority args are passed as an argument, it will call the appropriate method and if proto
130 * args are passed then the {@code asProto} flag is set.
Felipe Lemef4006d92016-10-07 17:57:13 -0700131 * <p>
Vishnu Nairf3648e02017-09-13 10:41:28 -0700132 * For example, if called as {@code --dump-priority HIGH arg1 arg2 arg3}, it will call
Vishnu Naire78b01a2017-10-26 10:11:54 -0700133 * <code>dumper.dumpHigh(fd, pw, {"arg1", "arg2", "arg3"}, false) </code>
Felipe Lemef4006d92016-10-07 17:57:13 -0700134 * <p>
Vishnu Nairf3648e02017-09-13 10:41:28 -0700135 * If the {@code --dump-priority} is not set, it calls
Vishnu Naire78b01a2017-10-26 10:11:54 -0700136 * {@link PriorityDumper#dump(FileDescriptor, PrintWriter, String[], boolean)} passing the whole
Felipe Lemef4006d92016-10-07 17:57:13 -0700137 * {@code args} instead.
138 */
139 public static void dump(PriorityDumper dumper, FileDescriptor fd, PrintWriter pw,
140 String[] args) {
Vishnu Naire78b01a2017-10-26 10:11:54 -0700141 boolean asProto = false;
142 @PriorityType int priority = PRIORITY_TYPE_INVALID;
143
144 if (args == null) {
145 dumper.dump(fd, pw, args, asProto);
146 return;
147 }
148
149 String[] strippedArgs = new String[args.length];
150 int strippedCount = 0;
151 for (int argIndex = 0; argIndex < args.length; argIndex++) {
152 if (args[argIndex].equals(PROTO_ARG)) {
153 asProto = true;
154 } else if (args[argIndex].equals(PRIORITY_ARG)) {
155 if (argIndex + 1 < args.length) {
156 argIndex++;
157 priority = getPriorityType(args[argIndex]);
Felipe Lemef4006d92016-10-07 17:57:13 -0700158 }
Vishnu Naire78b01a2017-10-26 10:11:54 -0700159 } else {
160 strippedArgs[strippedCount++] = args[argIndex];
Felipe Lemef4006d92016-10-07 17:57:13 -0700161 }
162 }
Vishnu Naire78b01a2017-10-26 10:11:54 -0700163
164 if (strippedCount < args.length) {
165 strippedArgs = Arrays.copyOf(strippedArgs, strippedCount);
166 }
167
168 switch (priority) {
169 case PRIORITY_TYPE_CRITICAL: {
170 dumper.dumpCritical(fd, pw, strippedArgs, asProto);
171 return;
172 }
173 case PRIORITY_TYPE_HIGH: {
174 dumper.dumpHigh(fd, pw, strippedArgs, asProto);
175 return;
176 }
177 case PRIORITY_TYPE_NORMAL: {
178 dumper.dumpNormal(fd, pw, strippedArgs, asProto);
179 return;
180 }
181 default: {
182 dumper.dump(fd, pw, strippedArgs, asProto);
183 return;
184 }
185 }
Felipe Lemef4006d92016-10-07 17:57:13 -0700186 }
187
188 /**
Vishnu Naire78b01a2017-10-26 10:11:54 -0700189 * Converts priority argument type to enum.
Felipe Lemef4006d92016-10-07 17:57:13 -0700190 */
Vishnu Naire78b01a2017-10-26 10:11:54 -0700191 private static @PriorityType int getPriorityType(String arg) {
192 switch (arg) {
Vishnu Naire3e4d252018-03-01 11:26:57 -0800193 case PRIORITY_ARG_CRITICAL: {
Vishnu Naire78b01a2017-10-26 10:11:54 -0700194 return PRIORITY_TYPE_CRITICAL;
195 }
Vishnu Naire3e4d252018-03-01 11:26:57 -0800196 case PRIORITY_ARG_HIGH: {
Vishnu Naire78b01a2017-10-26 10:11:54 -0700197 return PRIORITY_TYPE_HIGH;
198 }
Vishnu Naire3e4d252018-03-01 11:26:57 -0800199 case PRIORITY_ARG_NORMAL: {
Vishnu Naire78b01a2017-10-26 10:11:54 -0700200 return PRIORITY_TYPE_NORMAL;
201 }
Vishnu Naire3e4d252018-03-01 11:26:57 -0800202 default: {
203 return PRIORITY_TYPE_INVALID;
204 }
Vishnu Naire78b01a2017-10-26 10:11:54 -0700205 }
Felipe Lemef4006d92016-10-07 17:57:13 -0700206 }
207
208 /**
209 * Helper for {@link android.os.Binder#dump(java.io.FileDescriptor, String[])} that supports the
Vishnu Naire78b01a2017-10-26 10:11:54 -0700210 * {@link #PRIORITY_ARG} and {@link #PROTO_ARG} arguments.
Felipe Lemef4006d92016-10-07 17:57:13 -0700211 *
212 * @hide
213 */
Vishnu Naire78b01a2017-10-26 10:11:54 -0700214 public interface PriorityDumper {
Felipe Lemef4006d92016-10-07 17:57:13 -0700215
216 /**
217 * Dumps only the critical section.
218 */
219 @SuppressWarnings("unused")
Vishnu Naire78b01a2017-10-26 10:11:54 -0700220 default void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args,
221 boolean asProto) {
Felipe Lemef4006d92016-10-07 17:57:13 -0700222 }
223
224 /**
225 * Dumps only the high-priority section.
226 */
227 @SuppressWarnings("unused")
Vishnu Naire78b01a2017-10-26 10:11:54 -0700228 default void dumpHigh(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) {
Felipe Lemef4006d92016-10-07 17:57:13 -0700229 }
230
231 /**
232 * Dumps only the normal section.
233 */
234 @SuppressWarnings("unused")
Vishnu Naire78b01a2017-10-26 10:11:54 -0700235 default void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) {
Felipe Lemef4006d92016-10-07 17:57:13 -0700236 }
237
238 /**
239 * Dumps all sections.
240 * <p>
241 * This method is called when
Vishnu Naire3e4d252018-03-01 11:26:57 -0800242 * {@link PriorityDump#dump(PriorityDumper, FileDescriptor, PrintWriter, String[])}
Vishnu Naire78b01a2017-10-26 10:11:54 -0700243 * is called without priority arguments. By default, it calls the 3 {@code dumpTYPE}
244 * methods, so sub-classes just need to implement the priority types they support.
Felipe Lemef4006d92016-10-07 17:57:13 -0700245 */
246 @SuppressWarnings("unused")
Vishnu Naire78b01a2017-10-26 10:11:54 -0700247 default void dump(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) {
248 dumpCritical(fd, pw, args, asProto);
249 dumpHigh(fd, pw, args, asProto);
250 dumpNormal(fd, pw, args, asProto);
Felipe Lemef4006d92016-10-07 17:57:13 -0700251 }
252 }
253}