blob: 8387ce79ad7a1d68f173e5b4d396b261b87fcd04 [file] [log] [blame]
/*
* Copyright (C) 2021 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.car.pm;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A utility class to parse the window dump.
*/
class WindowDumpParser {
private static final String WINDOW_TYPE_APPLICATION_STARTING = "APPLICATION_STARTING";
/**
* Parses the provided window dump and returns the list of windows only for a particular app.
*
* @param dump the window dump in string format as returned from `dumpsys window
* windows`.
* @param appPackageName the package name of the app, which the windows are being
* requested for.
* @return a list of parsed {@link Window} objects.
*/
public static List<Window> getParsedAppWindows(String dump, String appPackageName) {
Pattern dumpSplitter = Pattern.compile("(Window #)|\\n\\n");
// \\n\\n to separate out the Global dump from the windows list.
Pattern windowDetailsPattern = Pattern.compile("\\d*.*\\n"
+ ".*mDisplayId=(\\S*).*\\n"
+ ".*package=(\\S*).*\\n"
+ ".*ty=(\\S*)"
+ "((.*ActivityRecord\\{(.*?)\\}.*\\n)|(.*\\n))*"
// (.*\\n) is required for skipping the lines before the line containing
// ActivityRecord{}.
);
List<Window> windows = new ArrayList<>();
String[] windowDumps = dumpSplitter.split(dump);
for (int i = 1; i < windowDumps.length - 1; i++) {
Matcher m = windowDetailsPattern.matcher(windowDumps[i]);
if (m.find()) {
// Only consider windows for the given appPackageName which are not the splash
// screen windows.
// TODO(b/192355798): Revisit this logic as window type can be changed.
if (Objects.equals(m.group(2), appPackageName)
&& !Objects.equals(m.group(3), WINDOW_TYPE_APPLICATION_STARTING)) {
windows.add(new Window(
/* packageName = */ m.group(2),
/* displayId = */ Integer.parseInt(m.group(1)),
/* activityRecord = */ m.group(6)
));
}
}
}
return windows;
}
/**
* A holder class that represents an app's window.
*/
static class Window {
private final String mPackageName;
private final int mDisplayId;
private final String mActivityRecord;
Window(String packageName, int displayId, String activityRecord) {
mPackageName = packageName;
mDisplayId = displayId;
mActivityRecord = activityRecord;
}
public String getPackageName() {
return mPackageName;
}
public int getDisplayId() {
return mDisplayId;
}
public String getActivityRecord() {
return mActivityRecord;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Window)) return false;
Window window = (Window) o;
return mDisplayId == window.mDisplayId
&& mPackageName.equals(window.mPackageName)
&& Objects.equals(mActivityRecord, window.mActivityRecord);
}
@Override
public int hashCode() {
return Objects.hash(mPackageName, mDisplayId, mActivityRecord);
}
@Override
public String toString() {
return "Window{"
+ "mPackageName=" + mPackageName
+ ", mDisplayId=" + mDisplayId
+ ", mActivityRecord={" + mActivityRecord + "}"
+ "}";
}
}
}