• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 android.server.wm;
18 
19 import static androidx.test.InstrumentationRegistry.getInstrumentation;
20 
21 import android.os.ParcelFileDescriptor;
22 
23 import java.io.File;
24 import java.io.FileInputStream;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.nio.charset.StandardCharsets;
28 
29 /* Captures WM dump through Perfetto. */
30 class WindowManagerTraceMonitor {
31     private static final File PERFETTO_TRACES_DIR = new File("/data/misc/perfetto-traces");
32     private static final String PERFETTO_CONFIG = """
33             unique_session_name: "cts-windowmanager-dump"
34             buffers: {
35                 size_kb: 65536
36                 fill_policy: RING_BUFFER
37             }
38             data_sources: {
39                 config {
40                     name: "android.windowmanager"
41                     windowmanager_config: {
42                         log_level: LOG_LEVEL_VERBOSE
43                         log_frequency: LOG_FREQUENCY_SINGLE_DUMP
44                     }
45                 }
46             }
47             duration_ms: 0
48             """;
49 
captureDump()50     byte[] captureDump() {
51         try {
52             String fileName =
53                     File.createTempFile("cts-windowmanager-dump-", ".perfetto-trace")
54                             .getName();
55             File traceFile = PERFETTO_TRACES_DIR.toPath().resolve(fileName).toFile();
56 
57             String command = "perfetto --background-wait" + " --config - --txt --out "
58                     + traceFile.getAbsolutePath();
59             String stdout = new String(executeShellCommand(command, PERFETTO_CONFIG.getBytes()),
60                     StandardCharsets.UTF_8);
61             int pid = Integer.parseInt(stdout.trim());
62 
63             killPerfettoProcess(pid);
64             waitPerfettoProcessExits(pid);
65 
66             byte[] dump = executeShellCommand("cat " + traceFile.getAbsolutePath());
67             return dump;
68         } catch (IOException e) {
69             throw new RuntimeException(e);
70         }
71     }
72 
killPerfettoProcess(int pid)73     private void killPerfettoProcess(int pid) {
74         if (isPerfettoProcessUp(pid)) {
75             executeShellCommand("kill " + pid);
76         }
77     }
78 
waitPerfettoProcessExits(int pid)79     private void waitPerfettoProcessExits(int pid) {
80         while (true) {
81             if (!isPerfettoProcessUp(pid)) {
82                 break;
83             }
84             try {
85                 Thread.sleep(50);
86             } catch (InterruptedException e) {
87                 throw new RuntimeException(e);
88             }
89         }
90     }
91 
isPerfettoProcessUp(int pid)92     private boolean isPerfettoProcessUp(int pid) {
93         String out =
94                 new String(executeShellCommand("ps -p " + pid + " -o PID"), StandardCharsets.UTF_8);
95         return out.contains(Integer.toString(pid));
96     }
97 
executeShellCommand(String command)98     private byte[] executeShellCommand(String command) {
99         StateLogger.log("Executing command: " + command);
100         try {
101             ParcelFileDescriptor fdStdout =
102                     getInstrumentation().getUiAutomation().executeShellCommand(command);
103             try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(fdStdout)) {
104                 return fis.readAllBytes();
105             }
106         } catch (IOException e) {
107             throw new RuntimeException(e);
108         }
109     }
110 
executeShellCommand(String command, byte[] stdin)111     private byte[] executeShellCommand(String command, byte[] stdin) {
112         StateLogger.log("Executing command: " + command);
113         try {
114             ParcelFileDescriptor[] fds = getInstrumentation().getUiAutomation()
115                     .executeShellCommandRw(command);
116 
117             ParcelFileDescriptor fdStdout = fds[0];
118             ParcelFileDescriptor fdStdin = fds[1];
119 
120             try (FileOutputStream fos = new ParcelFileDescriptor.AutoCloseOutputStream(fdStdin)) {
121                 fos.write(stdin);
122             }
123 
124             try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(fdStdout)) {
125                 byte[] stdout = fis.readAllBytes();
126                 return stdout;
127             }
128         } catch (IOException e) {
129             throw new RuntimeException(e);
130         }
131     }
132 }
133