1 /*
2  * Copyright (C) 2024 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.io
18 
19 import android.os.SystemClock
20 import android.tools.traces.executeShellCommand
21 import java.io.File
22 import java.nio.file.Files
23 import java.nio.file.Paths
24 
25 object IoUtils {
copyFilenull26     private fun copyFile(src: File, dst: File) {
27         executeShellCommand("cp $src $dst")
28         executeShellCommand("chmod a+r $dst")
29     }
30 
moveFilenull31     fun moveFile(src: File, dst: File) {
32         if (src.isDirectory) {
33             moveDirectory(src, dst)
34         }
35         // Move the  file to the output directory
36         // Note: Due to b/141386109, certain devices do not allow moving the files between
37         //       directories with different encryption policies, so manually copy and then
38         //       remove the original file
39         //       Moreover, the copied trace file may end up with different permissions, resulting
40         //       in b/162072200, to prevent this, ensure the files are readable after copying
41         copyFile(src, dst)
42         executeShellCommand("rm $src")
43     }
44 
waitFileExistsnull45     fun waitFileExists(file: File, timeoutMs: Long) {
46         val sleepIncrementMs = 50L
47         var elapsedMs = 0L
48 
49         while (elapsedMs < timeoutMs) {
50             val out = String(executeShellCommand("ls $file")).trim()
51             val configFileInPerfettoDirExists = out == file.toString()
52 
53             if (configFileInPerfettoDirExists) {
54                 return
55             }
56 
57             SystemClock.sleep(sleepIncrementMs)
58             elapsedMs += sleepIncrementMs
59         }
60 
61         error("Failed to wait for file to exist: $file. Timed out after $timeoutMs ms.")
62     }
63 
moveDirectorynull64     private fun moveDirectory(src: File, dst: File) {
65         require(src.isDirectory) { "$src is not a directory" }
66 
67         Files.createDirectories(Paths.get(dst.path))
68 
69         src.listFiles()?.forEach {
70             if (it.isDirectory) {
71                 moveDirectory(src, dst.resolve(it.name))
72             } else {
73                 moveFile(it, dst.resolve(it.name))
74             }
75         }
76     }
77 }
78