blob: b9dc9db7c5eee0bbaad22e65b714d90bc93a38fe [file] [log] [blame]
Adrian Roos111aff92017-09-27 18:11:46 +02001/*
2 * Copyright (C) 2017 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.wm;
18
Vishnu Nairab250032017-11-21 07:32:43 -080019import static android.os.Build.IS_USER;
20
Dianne Hackborn5c3296a2017-12-13 17:52:26 -080021import android.graphics.Point;
22import android.graphics.Rect;
23import android.os.ParcelFileDescriptor;
24import android.os.RemoteException;
Adrian Roos111aff92017-09-27 18:11:46 +020025import android.os.ShellCommand;
Dianne Hackborn5c3296a2017-12-13 17:52:26 -080026import android.os.UserHandle;
27import android.util.DisplayMetrics;
28import android.view.Display;
29import android.view.IWindowManager;
Adrian Roos111aff92017-09-27 18:11:46 +020030
Dianne Hackborn5c3296a2017-12-13 17:52:26 -080031import java.io.BufferedReader;
32import java.io.IOException;
33import java.io.InputStream;
34import java.io.InputStreamReader;
Adrian Roos111aff92017-09-27 18:11:46 +020035import java.io.PrintWriter;
Dianne Hackborn5c3296a2017-12-13 17:52:26 -080036import java.util.regex.Matcher;
37import java.util.regex.Pattern;
Adrian Roos111aff92017-09-27 18:11:46 +020038
39/**
40 * ShellCommands for WindowManagerService.
41 *
42 * Use with {@code adb shell cmd window ...}.
43 */
44public class WindowManagerShellCommand extends ShellCommand {
45
Dianne Hackborn5c3296a2017-12-13 17:52:26 -080046 // IPC interface to activity manager -- don't need to do additional security checks.
47 private final IWindowManager mInterface;
48
49 // Internal service impl -- must perform security checks before touching.
50 private final WindowManagerService mInternal;
Adrian Roos111aff92017-09-27 18:11:46 +020051
52 public WindowManagerShellCommand(WindowManagerService service) {
Dianne Hackborn5c3296a2017-12-13 17:52:26 -080053 mInterface = service;
54 mInternal = service;
Adrian Roos111aff92017-09-27 18:11:46 +020055 }
56
57 @Override
58 public int onCommand(String cmd) {
Dianne Hackborn5c3296a2017-12-13 17:52:26 -080059 if (cmd == null) {
60 return handleDefaultCommands(cmd);
Adrian Roos111aff92017-09-27 18:11:46 +020061 }
Dianne Hackborn5c3296a2017-12-13 17:52:26 -080062 final PrintWriter pw = getOutPrintWriter();
63 try {
64 switch (cmd) {
65 case "size":
66 return runDisplaySize(pw);
67 case "density":
68 return runDisplayDensity(pw);
69 case "overscan":
70 return runDisplayOverscan(pw);
71 case "scaling":
72 return runDisplayScaling(pw);
73 case "screen-capture":
74 return runSetScreenCapture(pw);
75 case "dismiss-keyguard":
76 return runDismissKeyguard(pw);
77 case "surface-trace":
78 return runSurfaceTrace(pw);
79 case "tracing":
80 // XXX this should probably be changed to use openFileForSystem() to create
81 // the output trace file, so the shell gets the correct semantics for where
82 // trace files can be written.
83 return mInternal.mWindowTracing.onShellCommand(this,
84 getNextArgRequired());
85 default:
86 return handleDefaultCommands(cmd);
87 }
88 } catch (RemoteException e) {
89 pw.println("Remote exception: " + e);
90 }
91 return -1;
92 }
93
94 private int runDisplaySize(PrintWriter pw) throws RemoteException {
95 String size = getNextArg();
96 int w, h;
97 if (size == null) {
98 Point initialSize = new Point();
99 Point baseSize = new Point();
100 try {
101 mInterface.getInitialDisplaySize(Display.DEFAULT_DISPLAY, initialSize);
102 mInterface.getBaseDisplaySize(Display.DEFAULT_DISPLAY, baseSize);
103 pw.println("Physical size: " + initialSize.x + "x" + initialSize.y);
104 if (!initialSize.equals(baseSize)) {
105 pw.println("Override size: " + baseSize.x + "x" + baseSize.y);
106 }
107 } catch (RemoteException e) {
108 }
109 return 0;
110 } else if ("reset".equals(size)) {
111 w = h = -1;
112 } else {
113 int div = size.indexOf('x');
114 if (div <= 0 || div >= (size.length()-1)) {
115 getErrPrintWriter().println("Error: bad size " + size);
116 return -1;
117 }
118 String wstr = size.substring(0, div);
119 String hstr = size.substring(div+1);
120 try {
121 w = parseDimension(wstr);
122 h = parseDimension(hstr);
123 } catch (NumberFormatException e) {
124 getErrPrintWriter().println("Error: bad number " + e);
125 return -1;
126 }
127 }
128
129 if (w >= 0 && h >= 0) {
130 // TODO(multidisplay): For now Configuration only applies to main screen.
131 mInterface.setForcedDisplaySize(Display.DEFAULT_DISPLAY, w, h);
132 } else {
133 mInterface.clearForcedDisplaySize(Display.DEFAULT_DISPLAY);
134 }
135 return 0;
136 }
137
138 private int runDisplayDensity(PrintWriter pw) throws RemoteException {
139 String densityStr = getNextArg();
140 int density;
141 if (densityStr == null) {
142 try {
143 int initialDensity = mInterface.getInitialDisplayDensity(Display.DEFAULT_DISPLAY);
144 int baseDensity = mInterface.getBaseDisplayDensity(Display.DEFAULT_DISPLAY);
145 pw.println("Physical density: " + initialDensity);
146 if (initialDensity != baseDensity) {
147 pw.println("Override density: " + baseDensity);
148 }
149 } catch (RemoteException e) {
150 }
151 return 0;
152 } else if ("reset".equals(densityStr)) {
153 density = -1;
154 } else {
155 try {
156 density = Integer.parseInt(densityStr);
157 } catch (NumberFormatException e) {
158 getErrPrintWriter().println("Error: bad number " + e);
159 return -1;
160 }
161 if (density < 72) {
162 getErrPrintWriter().println("Error: density must be >= 72");
163 return -1;
164 }
165 }
166
167 if (density > 0) {
168 // TODO(multidisplay): For now Configuration only applies to main screen.
169 mInterface.setForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, density,
170 UserHandle.USER_CURRENT);
171 } else {
172 mInterface.clearForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY,
173 UserHandle.USER_CURRENT);
174 }
175 return 0;
176 }
177
178 private int runDisplayOverscan(PrintWriter pw) throws RemoteException {
179 String overscanStr = getNextArgRequired();
180 Rect rect = new Rect();
181 if ("reset".equals(overscanStr)) {
182 rect.set(0, 0, 0, 0);
183 } else {
184 final Pattern FLATTENED_PATTERN = Pattern.compile(
185 "(-?\\d+),(-?\\d+),(-?\\d+),(-?\\d+)");
186 Matcher matcher = FLATTENED_PATTERN.matcher(overscanStr);
187 if (!matcher.matches()) {
188 getErrPrintWriter().println("Error: bad rectangle arg: " + overscanStr);
189 return -1;
190 }
191 rect.left = Integer.parseInt(matcher.group(1));
192 rect.top = Integer.parseInt(matcher.group(2));
193 rect.right = Integer.parseInt(matcher.group(3));
194 rect.bottom = Integer.parseInt(matcher.group(4));
195 }
196
197 mInterface.setOverscan(Display.DEFAULT_DISPLAY, rect.left, rect.top, rect.right,
198 rect.bottom);
199 return 0;
200 }
201
202 private int runDisplayScaling(PrintWriter pw) throws RemoteException {
203 String scalingStr = getNextArgRequired();
204 if ("auto".equals(scalingStr)) {
205 mInterface.setForcedDisplayScalingMode(Display.DEFAULT_DISPLAY, 0);
206 } else if ("off".equals(scalingStr)) {
207 mInterface.setForcedDisplayScalingMode(Display.DEFAULT_DISPLAY, 1);
208 } else {
209 getErrPrintWriter().println("Error: scaling must be 'auto' or 'off'");
210 return -1;
211 }
212 return 0;
213 }
214
215 private int runSetScreenCapture(PrintWriter pw) throws RemoteException {
216 String userIdStr = getNextArg();
217 String enableStr = getNextArg();
218 int userId;
219 boolean disable;
220
221 try {
222 userId = Integer.parseInt(userIdStr);
223 } catch (NumberFormatException e) {
224 getErrPrintWriter().println("Error: bad number " + e);
225 return -1;
226 }
227
228 disable = !Boolean.parseBoolean(enableStr);
229 mInternal.setScreenCaptureDisabled(userId, disable);
230 return 0;
231 }
232
233 private int runDismissKeyguard(PrintWriter pw) throws RemoteException {
234 mInterface.dismissKeyguard(null /* callback */);
235 return 0;
236 }
237
238 private int runSurfaceTrace(PrintWriter pw) throws RemoteException {
239 final ParcelFileDescriptor pfd;
240 try {
241 pfd = ParcelFileDescriptor.dup(getOutFileDescriptor());
242 } catch (IOException e) {
243 getErrPrintWriter().println("Unable to dup output stream: " + e.getMessage());
244 return -1;
245 }
246 mInternal.enableSurfaceTrace(pfd);
247
248 // Read input until an explicit quit command is sent or the stream is closed (meaning
249 // the user killed the command).
250 try {
251 InputStream input = getRawInputStream();
252 InputStreamReader converter = new InputStreamReader(input);
253 BufferedReader in = new BufferedReader(converter);
254 String line;
255
256 while ((line = in.readLine()) != null) {
257 if (line.length() <= 0) {
258 // no-op
259 } else if ("q".equals(line) || "quit".equals(line)) {
260 break;
261 } else {
262 pw.println("Invalid command: " + line);
263 }
264 }
265 } catch (IOException e) {
266 e.printStackTrace(pw);
267 } finally {
268 mInternal.disableSurfaceTrace();
269 try {
270 pfd.close();
271 } catch (IOException e) {
272 }
273 }
274
275 return 0;
276 }
277
278 private int parseDimension(String s) throws NumberFormatException {
279 if (s.endsWith("px")) {
280 return Integer.parseInt(s.substring(0, s.length() - 2));
281 }
282 if (s.endsWith("dp")) {
283 int density;
284 try {
285 density = mInterface.getBaseDisplayDensity(Display.DEFAULT_DISPLAY);
286 } catch (RemoteException e) {
287 density = DisplayMetrics.DENSITY_DEFAULT;
288 }
289 return Integer.parseInt(s.substring(0, s.length() - 2)) * density /
290 DisplayMetrics.DENSITY_DEFAULT;
291 }
292 return Integer.parseInt(s);
Adrian Roos111aff92017-09-27 18:11:46 +0200293 }
294
295 @Override
296 public void onHelp() {
297 PrintWriter pw = getOutPrintWriter();
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800298 pw.println("Window manager (window) commands:");
Adrian Roos111aff92017-09-27 18:11:46 +0200299 pw.println(" help");
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800300 pw.println(" Print this help text.");
301 pw.println(" size [reset|WxH|WdpxHdp]");
302 pw.println(" Return or override display size.");
303 pw.println(" width and height in pixels unless suffixed with 'dp'.");
304 pw.println(" density [reset|DENSITY]");
305 pw.println(" Return or override display density.");
306 pw.println(" overscan [reset|LEFT,TOP,RIGHT,BOTTOM]");
307 pw.println(" Set overscan area for display.");
308 pw.println(" scaling [off|auto]");
309 pw.println(" Set display scaling mode.");
310 pw.println(" screen-capture [userId] [true|false]");
311 pw.println(" Enable or disable screen capture.");
312 pw.println(" dismiss-keyguard");
313 pw.println(" Dismiss the keyguard, prompting user for auth if necessary.");
314 pw.println(" surface-trace");
315 pw.println(" Log surface commands to stdout in a binary format.");
316 if (!IS_USER) {
Vishnu Nairab250032017-11-21 07:32:43 -0800317 pw.println(" tracing (start | stop)");
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800318 pw.println(" Start or stop window tracing.");
Vishnu Nairab250032017-11-21 07:32:43 -0800319 }
Adrian Roos111aff92017-09-27 18:11:46 +0200320 }
321}