1 /*
<lambda>null2  * 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.tools.traces.monitors.view
18 
19 import android.tools.io.TraceType
20 import android.tools.traces.executeShellCommand
21 import android.tools.traces.io.ResultWriter
22 import android.tools.traces.monitors.LOG_TAG
23 import android.tools.traces.monitors.TraceMonitor
24 import android.util.Log
25 import java.io.File
26 import java.util.zip.ZipFile
27 
28 /** Captures View traces from Launcher. */
29 open class ViewTraceMonitor : TraceMonitor() {
30     override val traceType = TraceType.VIEW
31     override val isEnabled
32         get() =
33             String(executeShellCommand("su root settings get global view_capture_enabled"))
34                 .trim() == "1"
35 
36     override fun doStart() {
37         doEnableDisableTrace(enable = true)
38     }
39 
40     override fun doStop(): File {
41         val outputFileZip = dumpTraces()
42         doEnableDisableTrace(enable = false)
43         return outputFileZip
44     }
45 
46     override fun stop(writer: ResultWriter) {
47         val viewCaptureZip = doStop()
48         writer.writeTraces(viewCaptureZip)
49     }
50 
51     private fun dumpTraces(): File {
52         val outputFileZip = File.createTempFile(traceType.fileName, "")
53         val stdout = executeShellCommand("su root cmd launcherapps dump-view-hierarchies")
54         outputFileZip.writeBytes(stdout)
55         return outputFileZip
56     }
57 
58     private fun ResultWriter.writeTraces(viewCaptureZip: File) {
59         Log.d(LOG_TAG, "Uncompressing $viewCaptureZip from zip")
60         ZipFile(viewCaptureZip).use { zipFile ->
61             val entries = zipFile.entries()
62             while (entries.hasMoreElements()) {
63                 val entry = entries.nextElement()
64                 if (!entry.isDirectory) {
65                     Log.d(LOG_TAG, "Found ${entry.name}")
66                     val fileName = entry.name.split("/").last()
67                     zipFile.getInputStream(entry).use { inputStream ->
68                         val unzippedFile = File.createTempFile(traceType.fileName, fileName)
69                         unzippedFile.writeBytes(inputStream.readAllBytes())
70 
71                         addTraceResult(traceType, unzippedFile, tag = fileName)
72                     }
73                 }
74             }
75         }
76     }
77 
78     private fun doEnableDisableTrace(enable: Boolean) {
79         executeShellCommand(
80             "su root settings put global view_capture_enabled ${if (enable) "1" else "0"}"
81         )
82     }
83 }
84