blob: deb1c976aef4b872ec014f799c8a567c828cf076 [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.wm.flicker
import com.android.compatibility.common.util.SystemUtil
import com.android.server.wm.traces.common.MILLISECOND_AS_NANOSECONDS
import com.android.server.wm.traces.common.component.matchers.ComponentNameMatcher
import com.android.server.wm.traces.common.io.RunStatus
import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.TimeZone
object Utils {
private fun renameFile(src: File, dst: File) {
SystemUtil.runShellCommand("mv $src $dst")
}
private fun copyFile(src: File, dst: File) {
SystemUtil.runShellCommand("cp $src $dst")
SystemUtil.runShellCommand("chmod a+r $dst")
}
fun moveFile(src: File, dst: File) {
// Move the file to the output directory
// Note: Due to b/141386109, certain devices do not allow moving the files between
// directories with different encryption policies, so manually copy and then
// remove the original file
// Moreover, the copied trace file may end up with different permissions, resulting
// in b/162072200, to prevent this, ensure the files are readable after copying
copyFile(src, dst)
SystemUtil.runShellCommand("rm $src")
}
fun addStatusToFileName(traceFile: File, status: RunStatus) {
val newFileName = "${status.prefix}_${traceFile.name}"
val dst = traceFile.resolveSibling(newFileName)
renameFile(traceFile, dst)
}
fun componentMatcherParamsFromName(name: String): Pair<String, String> {
var packageName = ""
var className = ""
if (name.contains("/")) {
if (name.contains("#")) {
name.removeSuffix("#")
}
val splitString = name.split('/')
packageName = splitString[0]
className = splitString[1]
} else {
className = name
}
return Pair(packageName, className)
}
fun componentNameMatcherHardcoded(str: String): ComponentNameMatcher? {
return when (true) {
str.contains("NavigationBar0") -> ComponentNameMatcher.NAV_BAR
str.contains("Taskbar") -> ComponentNameMatcher.TASK_BAR
str.contains("StatusBar") -> ComponentNameMatcher.STATUS_BAR
str.contains("RotationLayer") -> ComponentNameMatcher.ROTATION
str.contains("BackColorSurface") -> ComponentNameMatcher.BACK_SURFACE
str.contains("InputMethod") -> ComponentNameMatcher.IME
str.contains("IME-snapshot-surface") -> ComponentNameMatcher.IME_SNAPSHOT
str.contains("Splash Screen") -> ComponentNameMatcher.SPLASH_SCREEN
str.contains("SnapshotStartingWindow") -> ComponentNameMatcher.SNAPSHOT
str.contains("Letterbox") -> ComponentNameMatcher.LETTERBOX
str.contains("Wallpaper BBQ wrapper") -> ComponentNameMatcher.WALLPAPER_BBQ_WRAPPER
str.contains("PipContentOverlay") -> ComponentNameMatcher.PIP_CONTENT_OVERLAY
str.contains("com.google.android.apps.nexuslauncher") -> ComponentNameMatcher.LAUNCHER
str.contains("StageCoordinatorSplitDivider") -> ComponentNameMatcher.SPLIT_DIVIDER
else -> null
}
}
/**
* Obtains the component name matcher corresponding to a name (str) Returns null if the name is
* not found in the hardcoded list, and it does not contain both the package and class name
* (with a / separator)
*/
fun componentNameMatcherFromName(
str: String,
): ComponentNameMatcher? {
return try {
componentNameMatcherHardcoded(str)
?: ComponentNameMatcher.unflattenFromStringWithJunk(str)
} catch (err: IllegalStateException) {
null
}
}
fun componentNameMatcherToString(componentNameMatcher: ComponentNameMatcher): String {
return "ComponentNameMatcher(\"${componentNameMatcher.packageName}\", " +
"\"${componentNameMatcher.className}\")"
}
fun componentNameMatcherToStringSimplified(componentNameMatcher: ComponentNameMatcher): String {
var className = componentNameMatcher.className
val separatedByDots = className.split('.')
if (separatedByDots.isNotEmpty()) {
className = separatedByDots[separatedByDots.size - 1]
}
className = className.replace(' ', '_')
return className
}
fun componentNameMatcherAsStringFromName(str: String): String? {
val componentMatcher = componentNameMatcherFromName(str)
return componentMatcher?.componentNameMatcherToString()
}
fun formatRealTimestamp(timestampNs: Long): String {
val timestampMs = timestampNs / MILLISECOND_AS_NANOSECONDS
val remainderNs = timestampNs % MILLISECOND_AS_NANOSECONDS
val date = Date(timestampMs)
val timeFormatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.ENGLISH)
timeFormatter.timeZone = TimeZone.getTimeZone("UTC")
return "${timeFormatter.format(date)}${remainderNs.toString().padStart(6, '0')}"
}
}