blob: e01cbf26dadc011ffec7343c745a7e469cd11e0c [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;
Dianne Hackborn5c3296a2017-12-13 17:52:26 -080023import android.os.RemoteException;
Adrian Roos111aff92017-09-27 18:11:46 +020024import android.os.ShellCommand;
Dianne Hackborn5c3296a2017-12-13 17:52:26 -080025import android.os.UserHandle;
26import android.util.DisplayMetrics;
27import android.view.Display;
28import android.view.IWindowManager;
Garfield Tan90c90052018-10-08 12:29:41 -070029import android.view.Surface;
Adrian Roos111aff92017-09-27 18:11:46 +020030
Adam Pardyl0f1b3d42019-08-19 15:24:11 +020031import com.android.server.protolog.ProtoLogImpl;
32
Adrian Roos111aff92017-09-27 18:11:46 +020033import java.io.PrintWriter;
Dianne Hackborn5c3296a2017-12-13 17:52:26 -080034import java.util.regex.Matcher;
35import java.util.regex.Pattern;
Adrian Roos111aff92017-09-27 18:11:46 +020036
37/**
38 * ShellCommands for WindowManagerService.
39 *
40 * Use with {@code adb shell cmd window ...}.
41 */
42public class WindowManagerShellCommand extends ShellCommand {
43
Dianne Hackborn5c3296a2017-12-13 17:52:26 -080044 // IPC interface to activity manager -- don't need to do additional security checks.
45 private final IWindowManager mInterface;
46
47 // Internal service impl -- must perform security checks before touching.
48 private final WindowManagerService mInternal;
Adrian Roos111aff92017-09-27 18:11:46 +020049
50 public WindowManagerShellCommand(WindowManagerService service) {
Dianne Hackborn5c3296a2017-12-13 17:52:26 -080051 mInterface = service;
52 mInternal = service;
Adrian Roos111aff92017-09-27 18:11:46 +020053 }
54
55 @Override
56 public int onCommand(String cmd) {
Dianne Hackborn5c3296a2017-12-13 17:52:26 -080057 if (cmd == null) {
58 return handleDefaultCommands(cmd);
Adrian Roos111aff92017-09-27 18:11:46 +020059 }
Dianne Hackborn5c3296a2017-12-13 17:52:26 -080060 final PrintWriter pw = getOutPrintWriter();
61 try {
62 switch (cmd) {
63 case "size":
64 return runDisplaySize(pw);
65 case "density":
66 return runDisplayDensity(pw);
Chilun70a9ab92019-02-12 10:57:49 +080067 case "folded-area":
68 return runDisplayFoldedArea(pw);
Dianne Hackborn5c3296a2017-12-13 17:52:26 -080069 case "overscan":
70 return runDisplayOverscan(pw);
71 case "scaling":
72 return runDisplayScaling(pw);
Dianne Hackborn5c3296a2017-12-13 17:52:26 -080073 case "dismiss-keyguard":
74 return runDismissKeyguard(pw);
Dianne Hackborn5c3296a2017-12-13 17:52:26 -080075 case "tracing":
76 // XXX this should probably be changed to use openFileForSystem() to create
77 // the output trace file, so the shell gets the correct semantics for where
78 // trace files can be written.
Nataniel Borges98d92aa2019-01-03 14:22:44 -080079 return mInternal.mWindowTracing.onShellCommand(this);
Adam Pardyl0f1b3d42019-08-19 15:24:11 +020080 case "logging":
81 return ProtoLogImpl.getSingleInstance().onShellCommand(this);
Garfield Tan90c90052018-10-08 12:29:41 -070082 case "set-user-rotation":
83 return runSetDisplayUserRotation(pw);
Garfield Tanff362222018-11-14 17:52:32 -080084 case "set-fix-to-user-rotation":
85 return runSetFixToUserRotation(pw);
Dianne Hackborn5c3296a2017-12-13 17:52:26 -080086 default:
87 return handleDefaultCommands(cmd);
88 }
89 } catch (RemoteException e) {
90 pw.println("Remote exception: " + e);
91 }
92 return -1;
93 }
94
Jeff Chang95aa5002018-09-06 16:34:10 +080095 private int getDisplayId(String opt) {
96 int displayId = Display.DEFAULT_DISPLAY;
97 String option = "-d".equals(opt) ? opt : getNextOption();
98 if (option != null && "-d".equals(option)) {
99 try {
100 displayId = Integer.parseInt(getNextArgRequired());
101 } catch (NumberFormatException e) {
102 getErrPrintWriter().println("Error: bad number " + e);
103 } catch (IllegalArgumentException e) {
104 getErrPrintWriter().println("Error: " + e);
105 }
106 }
107 return displayId;
108 }
109
110 private void printInitialDisplaySize(PrintWriter pw , int displayId) {
111 final Point initialSize = new Point();
112 final Point baseSize = new Point();
113
114 try {
115 mInterface.getInitialDisplaySize(displayId, initialSize);
116 mInterface.getBaseDisplaySize(displayId, baseSize);
117 pw.println("Physical size: " + initialSize.x + "x" + initialSize.y);
118 if (!initialSize.equals(baseSize)) {
119 pw.println("Override size: " + baseSize.x + "x" + baseSize.y);
120 }
121 } catch (RemoteException e) {
122 // Can't call getInitialDisplaySize() on IWindowManager or
123 // Can't call getBaseDisplaySize() on IWindowManager
124 pw.println("Remote exception: " + e);
125 }
126 }
127
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800128 private int runDisplaySize(PrintWriter pw) throws RemoteException {
129 String size = getNextArg();
130 int w, h;
Jeff Chang95aa5002018-09-06 16:34:10 +0800131 final int displayId = getDisplayId(size);
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800132 if (size == null) {
Jeff Chang95aa5002018-09-06 16:34:10 +0800133 printInitialDisplaySize(pw, displayId);
134 return 0;
135 } else if ("-d".equals(size)) {
136 printInitialDisplaySize(pw, displayId);
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800137 return 0;
138 } else if ("reset".equals(size)) {
139 w = h = -1;
140 } else {
141 int div = size.indexOf('x');
142 if (div <= 0 || div >= (size.length()-1)) {
143 getErrPrintWriter().println("Error: bad size " + size);
144 return -1;
145 }
146 String wstr = size.substring(0, div);
147 String hstr = size.substring(div+1);
148 try {
Jeff Chang95aa5002018-09-06 16:34:10 +0800149 w = parseDimension(wstr, displayId);
150 h = parseDimension(hstr, displayId);
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800151 } catch (NumberFormatException e) {
152 getErrPrintWriter().println("Error: bad number " + e);
153 return -1;
154 }
155 }
156
157 if (w >= 0 && h >= 0) {
Jeff Chang95aa5002018-09-06 16:34:10 +0800158 mInterface.setForcedDisplaySize(displayId, w, h);
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800159 } else {
Jeff Chang95aa5002018-09-06 16:34:10 +0800160 mInterface.clearForcedDisplaySize(displayId);
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800161 }
162 return 0;
163 }
164
Jeff Chang95aa5002018-09-06 16:34:10 +0800165 private void printInitialDisplayDensity(PrintWriter pw , int displayId) {
166 try {
167 final int initialDensity = mInterface.getInitialDisplayDensity(displayId);
168 final int baseDensity = mInterface.getBaseDisplayDensity(displayId);
169 pw.println("Physical density: " + initialDensity);
170 if (initialDensity != baseDensity) {
171 pw.println("Override density: " + baseDensity);
172 }
173 } catch (RemoteException e) {
174 // Can't call getInitialDisplayDensity() on IWindowManager or
175 // Can't call getBaseDisplayDensity() on IWindowManager
176 pw.println("Remote exception: " + e);
177 }
178 }
179
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800180 private int runDisplayDensity(PrintWriter pw) throws RemoteException {
181 String densityStr = getNextArg();
182 int density;
Jeff Chang95aa5002018-09-06 16:34:10 +0800183 final int displayId = getDisplayId(densityStr);
184
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800185 if (densityStr == null) {
Jeff Chang95aa5002018-09-06 16:34:10 +0800186 printInitialDisplayDensity(pw, displayId);
187 return 0;
188 } else if ("-d".equals(densityStr)) {
189 printInitialDisplayDensity(pw, displayId);
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800190 return 0;
191 } else if ("reset".equals(densityStr)) {
192 density = -1;
193 } else {
194 try {
195 density = Integer.parseInt(densityStr);
196 } catch (NumberFormatException e) {
197 getErrPrintWriter().println("Error: bad number " + e);
198 return -1;
199 }
200 if (density < 72) {
201 getErrPrintWriter().println("Error: density must be >= 72");
202 return -1;
203 }
204 }
205
206 if (density > 0) {
Jeff Chang95aa5002018-09-06 16:34:10 +0800207 mInterface.setForcedDisplayDensityForUser(displayId, density,
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800208 UserHandle.USER_CURRENT);
209 } else {
Jeff Chang95aa5002018-09-06 16:34:10 +0800210 mInterface.clearForcedDisplayDensityForUser(displayId,
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800211 UserHandle.USER_CURRENT);
212 }
213 return 0;
214 }
215
Chilun70a9ab92019-02-12 10:57:49 +0800216 private void printFoldedArea(PrintWriter pw) {
217 final Rect foldedArea = mInternal.getFoldedArea();
218 if (foldedArea.isEmpty()) {
219 pw.println("Folded area: none");
220 } else {
221 pw.println("Folded area: " + foldedArea.left + "," + foldedArea.top + ","
222 + foldedArea.right + "," + foldedArea.bottom);
223 }
224 }
225
226 private int runDisplayFoldedArea(PrintWriter pw) {
227 final String areaStr = getNextArg();
228 final Rect rect = new Rect();
229 if (areaStr == null) {
230 printFoldedArea(pw);
231 return 0;
232 } else if ("reset".equals(areaStr)) {
233 rect.setEmpty();
234 } else {
235 final Pattern flattenedPattern = Pattern.compile(
236 "(-?\\d+),(-?\\d+),(-?\\d+),(-?\\d+)");
237 final Matcher matcher = flattenedPattern.matcher(areaStr);
238 if (!matcher.matches()) {
239 getErrPrintWriter().println("Error: area should be LEFT,TOP,RIGHT,BOTTOM");
240 return -1;
241 }
242 rect.set(Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)),
243 Integer.parseInt(matcher.group(3)), Integer.parseInt(matcher.group(4)));
244 }
245
246 mInternal.setOverrideFoldedArea(rect);
247 return 0;
248 }
249
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800250 private int runDisplayOverscan(PrintWriter pw) throws RemoteException {
251 String overscanStr = getNextArgRequired();
252 Rect rect = new Rect();
Jeff Chang95aa5002018-09-06 16:34:10 +0800253 final int displayId = getDisplayId(overscanStr);
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800254 if ("reset".equals(overscanStr)) {
255 rect.set(0, 0, 0, 0);
256 } else {
257 final Pattern FLATTENED_PATTERN = Pattern.compile(
258 "(-?\\d+),(-?\\d+),(-?\\d+),(-?\\d+)");
259 Matcher matcher = FLATTENED_PATTERN.matcher(overscanStr);
260 if (!matcher.matches()) {
261 getErrPrintWriter().println("Error: bad rectangle arg: " + overscanStr);
262 return -1;
263 }
264 rect.left = Integer.parseInt(matcher.group(1));
265 rect.top = Integer.parseInt(matcher.group(2));
266 rect.right = Integer.parseInt(matcher.group(3));
267 rect.bottom = Integer.parseInt(matcher.group(4));
268 }
269
Jeff Chang95aa5002018-09-06 16:34:10 +0800270 mInterface.setOverscan(displayId, rect.left, rect.top, rect.right, rect.bottom);
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800271 return 0;
272 }
273
274 private int runDisplayScaling(PrintWriter pw) throws RemoteException {
275 String scalingStr = getNextArgRequired();
276 if ("auto".equals(scalingStr)) {
Riddle Hsuf53da812018-08-15 22:00:27 +0800277 mInterface.setForcedDisplayScalingMode(getDisplayId(scalingStr),
278 DisplayContent.FORCE_SCALING_MODE_AUTO);
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800279 } else if ("off".equals(scalingStr)) {
Riddle Hsuf53da812018-08-15 22:00:27 +0800280 mInterface.setForcedDisplayScalingMode(getDisplayId(scalingStr),
281 DisplayContent.FORCE_SCALING_MODE_DISABLED);
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800282 } else {
283 getErrPrintWriter().println("Error: scaling must be 'auto' or 'off'");
284 return -1;
285 }
286 return 0;
287 }
288
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800289 private int runDismissKeyguard(PrintWriter pw) throws RemoteException {
Lucas Dupinc80c67e2017-12-04 14:29:10 -0800290 mInterface.dismissKeyguard(null /* callback */, null /* message */);
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800291 return 0;
292 }
293
Jeff Chang95aa5002018-09-06 16:34:10 +0800294 private int parseDimension(String s, int displayId) throws NumberFormatException {
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800295 if (s.endsWith("px")) {
296 return Integer.parseInt(s.substring(0, s.length() - 2));
297 }
298 if (s.endsWith("dp")) {
299 int density;
300 try {
Jeff Chang95aa5002018-09-06 16:34:10 +0800301 density = mInterface.getBaseDisplayDensity(displayId);
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800302 } catch (RemoteException e) {
303 density = DisplayMetrics.DENSITY_DEFAULT;
304 }
305 return Integer.parseInt(s.substring(0, s.length() - 2)) * density /
306 DisplayMetrics.DENSITY_DEFAULT;
307 }
308 return Integer.parseInt(s);
Adrian Roos111aff92017-09-27 18:11:46 +0200309 }
310
Garfield Tan90c90052018-10-08 12:29:41 -0700311 private int runSetDisplayUserRotation(PrintWriter pw) {
312 final String lockMode = getNextArgRequired();
313
314 int displayId = Display.DEFAULT_DISPLAY;
315 String arg = getNextArg();
316 if ("-d".equals(arg)) {
317 displayId = Integer.parseInt(getNextArgRequired());
318 arg = getNextArg();
319 }
320
321 if ("free".equals(lockMode)) {
322 mInternal.thawDisplayRotation(displayId);
323 return 0;
324 }
325
326 if (!lockMode.equals("lock")) {
327 getErrPrintWriter().println("Error: lock mode needs to be either free or lock.");
328 return -1;
329 }
330
331 try {
332 final int rotation = arg != null ? Integer.parseInt(arg) : Surface.ROTATION_0;
333 mInternal.freezeDisplayRotation(displayId, rotation);
334 return 0;
335 } catch (IllegalArgumentException e) {
336 getErrPrintWriter().println("Error: " + e.getMessage());
337 return -1;
338 }
339 }
340
Garfield Tanff362222018-11-14 17:52:32 -0800341 private int runSetFixToUserRotation(PrintWriter pw) {
342 int displayId = Display.DEFAULT_DISPLAY;
343 String arg = getNextArgRequired();
344 if ("-d".equals(arg)) {
345 displayId = Integer.parseInt(getNextArgRequired());
346 arg = getNextArgRequired();
347 }
348
Garfield Tan7fbca052019-02-19 10:45:35 -0800349 final @DisplayRotation.FixedToUserRotation int fixedToUserRotation;
Garfield Tanff362222018-11-14 17:52:32 -0800350 switch (arg) {
351 case "enabled":
Garfield Tan7fbca052019-02-19 10:45:35 -0800352 fixedToUserRotation = DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED;
Garfield Tanff362222018-11-14 17:52:32 -0800353 break;
354 case "disabled":
Garfield Tan7fbca052019-02-19 10:45:35 -0800355 fixedToUserRotation = DisplayRotation.FIXED_TO_USER_ROTATION_DISABLED;
356 break;
357 case "default":
358 fixedToUserRotation = DisplayRotation.FIXED_TO_USER_ROTATION_DISABLED;
Garfield Tanff362222018-11-14 17:52:32 -0800359 break;
360 default:
Garfield Tan7fbca052019-02-19 10:45:35 -0800361 getErrPrintWriter().println("Error: expecting enabled, disabled or default, but we "
362 + "get " + arg);
Garfield Tanff362222018-11-14 17:52:32 -0800363 return -1;
364 }
365
Garfield Tan7fbca052019-02-19 10:45:35 -0800366 mInternal.setRotateForApp(displayId, fixedToUserRotation);
Garfield Tanff362222018-11-14 17:52:32 -0800367 return 0;
368 }
369
Adrian Roos111aff92017-09-27 18:11:46 +0200370 @Override
371 public void onHelp() {
372 PrintWriter pw = getOutPrintWriter();
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800373 pw.println("Window manager (window) commands:");
Adrian Roos111aff92017-09-27 18:11:46 +0200374 pw.println(" help");
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800375 pw.println(" Print this help text.");
Jeff Chang95aa5002018-09-06 16:34:10 +0800376 pw.println(" size [reset|WxH|WdpxHdp] [-d DISPLAY_ID]");
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800377 pw.println(" Return or override display size.");
378 pw.println(" width and height in pixels unless suffixed with 'dp'.");
Jeff Chang95aa5002018-09-06 16:34:10 +0800379 pw.println(" density [reset|DENSITY] [-d DISPLAY_ID]");
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800380 pw.println(" Return or override display density.");
Chilun70a9ab92019-02-12 10:57:49 +0800381 pw.println(" folded-area [reset|LEFT,TOP,RIGHT,BOTTOM]");
382 pw.println(" Return or override folded area.");
Jeff Chang95aa5002018-09-06 16:34:10 +0800383 pw.println(" overscan [reset|LEFT,TOP,RIGHT,BOTTOM] [-d DISPLAY ID]");
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800384 pw.println(" Set overscan area for display.");
Jeff Chang95aa5002018-09-06 16:34:10 +0800385 pw.println(" scaling [off|auto] [-d DISPLAY_ID]");
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800386 pw.println(" Set display scaling mode.");
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800387 pw.println(" dismiss-keyguard");
388 pw.println(" Dismiss the keyguard, prompting user for auth if necessary.");
Garfield Tan90c90052018-10-08 12:29:41 -0700389 pw.println(" set-user-rotation [free|lock] [-d DISPLAY_ID] [rotation]");
390 pw.println(" Set user rotation mode and user rotation.");
Garfield Tanff362222018-11-14 17:52:32 -0800391 pw.println(" set-fix-to-user-rotation [-d DISPLAY_ID] [enabled|disabled]");
392 pw.println(" Enable or disable rotating display for app requested orientation.");
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800393 if (!IS_USER) {
Vishnu Nairab250032017-11-21 07:32:43 -0800394 pw.println(" tracing (start | stop)");
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800395 pw.println(" Start or stop window tracing.");
Adam Pardyl0f1b3d42019-08-19 15:24:11 +0200396 pw.println(" logging (start | stop | enable | disable | enable-text | disable-text)");
397 pw.println(" Logging settings.");
Vishnu Nairab250032017-11-21 07:32:43 -0800398 }
Adrian Roos111aff92017-09-27 18:11:46 +0200399 }
400}