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