Compressing view capture data and changing the format to avoid
storing duplicate strings
Also starting the dump process early to avoid timeouts
Bug: 242868825
Test: Verified on web-hv UI tool
Change-Id: I9943e41426f820c9ab70d39b9f01896ed060cab4
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 761f198..4a52d3e 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1491,9 +1491,9 @@
if (FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) {
View root = getDragLayer().getRootView();
if (mViewCapture != null) {
- root.getViewTreeObserver().removeOnDrawListener(mViewCapture);
+ mViewCapture.detach();
}
- mViewCapture = new ViewCapture(root);
+ mViewCapture = new ViewCapture(getWindow());
mViewCapture.attach();
}
}
@@ -1501,6 +1501,10 @@
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
+ if (mViewCapture != null) {
+ mViewCapture.detach();
+ mViewCapture = null;
+ }
mOverlayManager.onDetachedFromWindow();
closeContextMenu();
}
@@ -2981,6 +2985,7 @@
*/
@Override
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+ SafeCloseable viewDump = mViewCapture == null ? null : mViewCapture.beginDump(writer, fd);
super.dump(prefix, fd, writer, args);
if (args.length > 0 && TextUtils.equals(args[0], "--all")) {
@@ -3015,19 +3020,16 @@
writer.println(prefix + "\tmRotationHelper: " + mRotationHelper);
writer.println(prefix + "\tmAppWidgetHost.isListening: " + mAppWidgetHost.isListening());
- if (mViewCapture != null) {
- writer.print(prefix + "\tmViewCapture: ");
- writer.flush();
- mViewCapture.dump(fd);
- writer.println();
- }
-
// Extra logging for general debugging
mDragLayer.dump(prefix, writer);
mStateManager.dump(prefix, writer);
mPopupDataProvider.dump(prefix, writer);
mDeviceProfile.dump(this, prefix, writer);
+ if (viewDump != null) {
+ viewDump.close();
+ }
+
try {
FileLog.flushAll(writer);
} catch (Exception e) {
diff --git a/src/com/android/launcher3/util/ViewCapture.java b/src/com/android/launcher3/util/ViewCapture.java
index 58c8269..e368ac3 100644
--- a/src/com/android/launcher3/util/ViewCapture.java
+++ b/src/com/android/launcher3/util/ViewCapture.java
@@ -15,18 +15,23 @@
*/
package com.android.launcher3.util;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+import static java.util.stream.Collectors.toList;
+
import android.content.res.Resources;
import android.os.Handler;
import android.os.Message;
import android.os.Trace;
+import android.text.TextUtils;
import android.util.Base64;
import android.util.Base64OutputStream;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver.OnDrawListener;
+import android.view.Window;
import androidx.annotation.UiThread;
import androidx.annotation.WorkerThread;
@@ -38,7 +43,10 @@
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.concurrent.Future;
+import java.util.zip.GZIPOutputStream;
/**
* Utility class for capturing view data every frame
@@ -53,6 +61,7 @@
// Launcher. This allows the first free frames avoid object allocation during view capture.
private static final int INIT_POOL_SIZE = 300;
+ private final Window mWindow;
private final View mRoot;
private final Resources mResources;
@@ -67,11 +76,12 @@
private ViewRef mPool = new ViewRef();
/**
- * @param root the root view for the capture data
+ * @param window the window for the capture data
*/
- public ViewCapture(View root) {
- mRoot = root;
- mResources = root.getResources();
+ public ViewCapture(Window window) {
+ mWindow = window;
+ mRoot = mWindow.getDecorView();
+ mResources = mRoot.getResources();
mHandler = new Handler(UI_HELPER_EXECUTOR.getLooper(), this::captureViewPropertiesBg);
}
@@ -82,6 +92,14 @@
mHandler.post(this::initPool);
}
+ /**
+ * Removes a previously attached ViewCapture from the root
+ */
+ public void detach() {
+ mHandler.post(() -> MAIN_EXECUTOR.execute(
+ () -> mRoot.getViewTreeObserver().removeOnDrawListener(this)));
+ }
+
@Override
public void onDraw() {
Trace.beginSection("view_capture");
@@ -139,7 +157,7 @@
}
mNodesBg[mFrameIndexBg] = result;
ViewRef end = last;
- Executors.MAIN_EXECUTOR.execute(() -> addToPool(start, end));
+ MAIN_EXECUTOR.execute(() -> addToPool(start, end));
return true;
}
@@ -160,7 +178,7 @@
}
ViewRef end = current;
- Executors.MAIN_EXECUTOR.execute(() -> {
+ MAIN_EXECUTOR.execute(() -> {
addToPool(start, end);
if (mRoot.isAttachedToWindow()) {
mRoot.getViewTreeObserver().addOnDrawListener(this);
@@ -168,38 +186,58 @@
});
}
+ private String getName() {
+ String title = mWindow.getAttributes().getTitle().toString();
+ return TextUtils.isEmpty(title) ? mWindow.toString() : title;
+ }
+
/**
- * Creates a proto of all the data captured so far.
+ * Starts the dump process which is completed on closing the returned object.
*/
- public void dump(FileDescriptor out) {
+ public SafeCloseable beginDump(PrintWriter writer, FileDescriptor out) {
Future<ExportedData> task = UI_HELPER_EXECUTOR.submit(this::dumpToProto);
- try (OutputStream os = new FileOutputStream(out)) {
- ExportedData data = task.get();
- Base64OutputStream encodedOS = new Base64OutputStream(os,
- Base64.NO_CLOSE | Base64.NO_PADDING | Base64.NO_WRAP);
- data.writeTo(encodedOS);
- encodedOS.close();
- os.flush();
- } catch (Exception e) {
- Log.e(TAG, "Error capturing proto", e);
- }
+
+ return () -> {
+ writer.println();
+ writer.println(" ContinuousViewCapture:");
+ writer.println(" window " + getName() + ":");
+ writer.println(" pkg:" + mRoot.getContext().getPackageName());
+ writer.print(" data:");
+ writer.flush();
+
+ try (OutputStream os = new FileOutputStream(out)) {
+ ExportedData data = task.get();
+ OutputStream encodedOS = new GZIPOutputStream(new Base64OutputStream(os,
+ Base64.NO_CLOSE | Base64.NO_PADDING | Base64.NO_WRAP));
+ data.writeTo(encodedOS);
+ encodedOS.close();
+ os.flush();
+ } catch (Exception e) {
+ Log.e(TAG, "Error capturing proto", e);
+ }
+ writer.println();
+ writer.println("--end--");
+ };
}
@WorkerThread
private ExportedData dumpToProto() {
ExportedData.Builder dataBuilder = ExportedData.newBuilder();
Resources res = mResources;
+ ArrayList<Class> classList = new ArrayList<>();
int size = (mNodesBg[MEMORY_SIZE - 1] == null) ? mFrameIndexBg + 1 : MEMORY_SIZE;
for (int i = size - 1; i >= 0; i--) {
int index = (MEMORY_SIZE + mFrameIndexBg - i) % MEMORY_SIZE;
ViewNode.Builder nodeBuilder = ViewNode.newBuilder();
- mNodesBg[index].toProto(res, nodeBuilder);
+ mNodesBg[index].toProto(res, classList, nodeBuilder);
dataBuilder.addFrameData(FrameData.newBuilder()
.setNode(nodeBuilder)
.setTimestamp(mFrameTimesBg[index]));
}
- return dataBuilder.build();
+ return dataBuilder
+ .addAllClassname(classList.stream().map(Class::getName).collect(toList()))
+ .build();
}
private ViewRef captureViewTree(View view, ViewRef start) {
@@ -278,10 +316,10 @@
/**
* Converts the data to the proto representation and returns the next property ref
* at the end of the iteration.
- * @param res
* @return
*/
- public ViewPropertyRef toProto(Resources res, ViewNode.Builder outBuilder) {
+ public ViewPropertyRef toProto(Resources res, ArrayList<Class> classList,
+ ViewNode.Builder outBuilder) {
String resolvedId;
if (id >= 0) {
try {
@@ -292,7 +330,14 @@
} else {
resolvedId = "NO_ID";
}
- outBuilder.setClassname(clazz.getName() + "@" + hashCode)
+ int classnameIndex = classList.indexOf(clazz);
+ if (classnameIndex < 0) {
+ classnameIndex = classList.size();
+ classList.add(clazz);
+ }
+ outBuilder
+ .setClassnameIndex(classnameIndex)
+ .setHashcode(hashCode)
.setId(resolvedId)
.setLeft(left)
.setTop(top)
@@ -311,7 +356,7 @@
ViewPropertyRef result = next;
for (int i = 0; (i < childCount) && (result != null); i++) {
ViewNode.Builder childBuilder = ViewNode.newBuilder();
- result = result.toProto(res, childBuilder);
+ result = result.toProto(res, classList, childBuilder);
outBuilder.addChildren(childBuilder);
}
return result;