mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-20 03:08:19 +00:00
Merge "Compressing view capture data and changing the format to avoid storing duplicate strings" into tm-qpr-dev am: 56677c50bd
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/19638802 Change-Id: I831b519a98e099d998ef4e04c7bcfc0114bb8454 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -23,6 +23,7 @@ option java_outer_classname = "ViewCaptureData";
|
||||
message ExportedData {
|
||||
|
||||
repeated FrameData frameData = 1;
|
||||
repeated string classname = 2;
|
||||
}
|
||||
|
||||
message FrameData {
|
||||
@@ -31,26 +32,28 @@ message FrameData {
|
||||
}
|
||||
|
||||
message ViewNode {
|
||||
optional string classname = 1;
|
||||
optional string id = 2;
|
||||
optional int32 left = 3;
|
||||
optional int32 top = 4;
|
||||
optional int32 width = 5;
|
||||
optional int32 height = 6;
|
||||
optional int32 scrollX = 7;
|
||||
optional int32 scrollY = 8;
|
||||
optional int32 classname_index = 1;
|
||||
optional int32 hashcode = 2;
|
||||
|
||||
optional float translationX = 9;
|
||||
optional float translationY = 10;
|
||||
optional float scaleX = 11 [default = 1];
|
||||
optional float scaleY = 12 [default = 1];
|
||||
optional float alpha = 13 [default = 1];
|
||||
repeated ViewNode children = 3;
|
||||
|
||||
optional bool willNotDraw = 14;
|
||||
optional bool clipChildren = 15;
|
||||
optional int32 visibility = 16;
|
||||
optional string id = 4;
|
||||
optional int32 left = 5;
|
||||
optional int32 top = 6;
|
||||
optional int32 width = 7;
|
||||
optional int32 height = 8;
|
||||
optional int32 scrollX = 9;
|
||||
optional int32 scrollY = 10;
|
||||
|
||||
repeated ViewNode children = 17;
|
||||
optional float translationX = 11;
|
||||
optional float translationY = 12;
|
||||
optional float scaleX = 13 [default = 1];
|
||||
optional float scaleY = 14 [default = 1];
|
||||
optional float alpha = 15 [default = 1];
|
||||
|
||||
optional float elevation = 18;
|
||||
optional bool willNotDraw = 16;
|
||||
optional bool clipChildren = 17;
|
||||
optional int32 visibility = 18;
|
||||
|
||||
optional float elevation = 19;
|
||||
}
|
||||
|
||||
@@ -1491,9 +1491,9 @@ public class Launcher extends StatefulActivity<LauncherState>
|
||||
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 @@ public class Launcher extends StatefulActivity<LauncherState>
|
||||
@Override
|
||||
public void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
if (mViewCapture != null) {
|
||||
mViewCapture.detach();
|
||||
mViewCapture = null;
|
||||
}
|
||||
mOverlayManager.onDetachedFromWindow();
|
||||
closeContextMenu();
|
||||
}
|
||||
@@ -2981,6 +2985,7 @@ public class Launcher extends StatefulActivity<LauncherState>
|
||||
*/
|
||||
@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 @@ public class Launcher extends StatefulActivity<LauncherState>
|
||||
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) {
|
||||
|
||||
@@ -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 com.android.launcher3.view.ViewCaptureData.ViewNode;
|
||||
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 @@ public class ViewCapture implements OnDrawListener {
|
||||
// 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 @@ public class ViewCapture implements OnDrawListener {
|
||||
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 @@ public class ViewCapture implements OnDrawListener {
|
||||
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 @@ public class ViewCapture implements OnDrawListener {
|
||||
}
|
||||
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 @@ public class ViewCapture implements OnDrawListener {
|
||||
}
|
||||
|
||||
ViewRef end = current;
|
||||
Executors.MAIN_EXECUTOR.execute(() -> {
|
||||
MAIN_EXECUTOR.execute(() -> {
|
||||
addToPool(start, end);
|
||||
if (mRoot.isAttachedToWindow()) {
|
||||
mRoot.getViewTreeObserver().addOnDrawListener(this);
|
||||
@@ -168,38 +186,58 @@ public class ViewCapture implements OnDrawListener {
|
||||
});
|
||||
}
|
||||
|
||||
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 @@ public class ViewCapture implements OnDrawListener {
|
||||
/**
|
||||
* 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 @@ public class ViewCapture implements OnDrawListener {
|
||||
} 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 @@ public class ViewCapture implements OnDrawListener {
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user