Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 88f7f5cc authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 11914274 from 9cde09e3 to 24Q3-release

Change-Id: I8c24735311f626a3a2c94f180ba8deea5d1d7537
parents 2848ce47 9cde09e3
Loading
Loading
Loading
Loading
+14 −3
Original line number Diff line number Diff line
@@ -583,7 +583,12 @@ public abstract class BaseIconCache {
                            PackageManager.PackageInfoFlags.of(flags));
                    ApplicationInfo appInfo = info.applicationInfo;
                    if (appInfo == null) {
                        throw new NameNotFoundException("ApplicationInfo is null");
                        NameNotFoundException e = new NameNotFoundException(
                                "ApplicationInfo is null");
                        logdPersistently(TAG,
                                String.format("ApplicationInfo is null for %s", packageName),
                                e);
                        throw e;
                    }

                    BaseIconFactory li = getIconFactory();
@@ -591,8 +596,9 @@ public abstract class BaseIconCache {
                    // only keep the low resolution icon instead of the larger full-sized icon
                    Drawable appIcon = appInfo.loadIcon(mPackageManager);
                    if (mPackageManager.isDefaultApplicationIcon(appIcon)) {
                        // TODO(b/343233224): Log in more persistent location such as FileLog.
                        Log.d(TAG, String.format("Default icon returned for %s", packageName));
                        logdPersistently(TAG,
                                String.format("Default icon returned for %s", packageName),
                                null);
                    }
                    BitmapInfo iconInfo = li.createBadgedIconBitmap(appIcon,
                            new IconOptions().setUser(user).setInstantApp(isInstantApp(appInfo)));
@@ -809,4 +815,9 @@ public abstract class BaseIconCache {
            throw new IllegalStateException("Cache accessed on wrong thread " + Looper.myLooper());
        }
    }

    /** Log to Log.d. Subclasses can override this method to log persistently for debugging. */
    protected void logdPersistently(String tag, String message, @Nullable Exception e) {
        Log.d(tag, message, e);
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -40,7 +40,7 @@ android_library {
    name: "motion_tool_lib",
    manifest: "AndroidManifest.xml",
    platform_apis: true,
    min_sdk_version: "26",
    min_sdk_version: "30",

    static_libs: [
        "androidx.core_core",
@@ -58,7 +58,7 @@ android_test {
    name: "motion_tool_lib_tests",
    manifest: "tests/AndroidManifest.xml",
    platform_apis: true,
    min_sdk_version: "26",
    min_sdk_version: "30",

    static_libs: [
        "androidx.core_core",
+3 −2
Original line number Diff line number Diff line
@@ -34,11 +34,12 @@ android_library {
    name: "view_capture",
    manifest: "AndroidManifest.xml",
    platform_apis: true,
    min_sdk_version: "26",
    min_sdk_version: "30",

    static_libs: [
        "androidx.core_core",
        "view_capture_proto",
        "perfetto_trace_javastream_protos_jarjar",
    ],

    srcs: [
@@ -51,7 +52,7 @@ android_test {
    name: "view_capture_tests",
    manifest: "tests/AndroidManifest.xml",
    platform_apis: true,
    min_sdk_version: "26",
    min_sdk_version: "30",

    static_libs: [
        "androidx.core_core",
+325 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.app.viewcapture

import android.content.Context
import android.internal.perfetto.protos.InternedDataOuterClass.InternedData
import android.internal.perfetto.protos.ProfileCommon.InternedString
import android.internal.perfetto.protos.TracePacketOuterClass.TracePacket
import android.internal.perfetto.protos.Viewcapture.ViewCapture as ViewCaptureMessage
import android.internal.perfetto.protos.WinscopeExtensionsImplOuterClass.WinscopeExtensionsImpl
import android.os.Trace
import android.tracing.perfetto.DataSourceParams
import android.tracing.perfetto.InitArguments
import android.tracing.perfetto.Producer
import android.util.proto.ProtoOutputStream
import androidx.annotation.WorkerThread
import java.util.concurrent.Executor
import java.util.concurrent.atomic.AtomicInteger

/**
 * ViewCapture that listens to Perfetto events (OnStart, OnStop, OnFlush) and continuously writes
 * captured frames to the Perfetto service (traced).
 */
internal class PerfettoViewCapture
internal constructor(private val context: Context, executor: Executor) :
    ViewCapture(RING_BUFFER_SIZE, DEFAULT_INIT_POOL_SIZE, executor) {

    private val mDataSource =
        ViewCaptureDataSource(
            { mActiveSessions.incrementAndGet() },
            {},
            { mActiveSessions.decrementAndGet() }
        )

    private val mActiveSessions = AtomicInteger(0)

    private val mViewIdProvider = ViewIdProvider(context.getResources())

    private var mSerializationCurrentId: Int = 0
    private var mSerializationCurrentView: ViewPropertyRef? = null

    inner class NewInternedStrings {
        val packageNames = mutableListOf<String>()
        val windowNames = mutableListOf<String>()
        val viewIds = mutableListOf<String>()
        val classNames = mutableListOf<String>()
    }

    init {
        Producer.init(InitArguments.DEFAULTS)
        val params =
            DataSourceParams.Builder()
                .setBufferExhaustedPolicy(
                    DataSourceParams.PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_STALL_AND_ABORT
                )
                .setNoFlush(true)
                .setWillNotifyOnStop(false)
                .build()
        mDataSource.register(params)
    }

    @WorkerThread
    override fun onCapturedViewPropertiesBg(
        elapsedRealtimeNanos: Long,
        windowName: String,
        startFlattenedTree: ViewPropertyRef
    ) {
        Trace.beginSection("vc#onCapturedViewPropertiesBg")

        mDataSource.trace { ctx ->
            val newInternedStrings = NewInternedStrings()
            val os = ctx.newTracePacket()
            os.write(TracePacket.TIMESTAMP, elapsedRealtimeNanos)
            serializeViews(
                os,
                windowName,
                startFlattenedTree,
                ctx.incrementalState,
                newInternedStrings
            )
            serializeIncrementalState(os, ctx.incrementalState, newInternedStrings)
        }

        Trace.endSection()
    }

    private fun serializeViews(
        os: ProtoOutputStream,
        windowName: String,
        startFlattenedTree: ViewPropertyRef,
        incrementalState: ViewCaptureDataSource.IncrementalState,
        newInternedStrings: NewInternedStrings
    ) {
        mSerializationCurrentView = startFlattenedTree
        mSerializationCurrentId = 0

        val tokenExtensions = os.start(TracePacket.WINSCOPE_EXTENSIONS)
        val tokenViewCapture = os.start(WinscopeExtensionsImpl.VIEWCAPTURE)
        os.write(
            ViewCaptureMessage.PACKAGE_NAME_IID,
            internPackageName(context.packageName, incrementalState, newInternedStrings)
        )
        os.write(
            ViewCaptureMessage.WINDOW_NAME_IID,
            internWindowName(windowName, incrementalState, newInternedStrings)
        )
        serializeViewsRec(os, -1, incrementalState, newInternedStrings)
        os.end(tokenViewCapture)
        os.end(tokenExtensions)
    }

    private fun serializeViewsRec(
        os: ProtoOutputStream,
        parentId: Int,
        incrementalState: ViewCaptureDataSource.IncrementalState,
        newInternedStrings: NewInternedStrings
    ) {
        if (mSerializationCurrentView == null) {
            return
        }

        val id = mSerializationCurrentId
        val childCount = mSerializationCurrentView!!.childCount

        serializeView(
            os,
            mSerializationCurrentView!!,
            mSerializationCurrentId,
            parentId,
            incrementalState,
            newInternedStrings
        )

        ++mSerializationCurrentId
        mSerializationCurrentView = mSerializationCurrentView!!.next

        for (i in 0..childCount - 1) {
            serializeViewsRec(os, id, incrementalState, newInternedStrings)
        }
    }

    private fun serializeView(
        os: ProtoOutputStream,
        view: ViewPropertyRef,
        id: Int,
        parentId: Int,
        incrementalState: ViewCaptureDataSource.IncrementalState,
        newInternedStrings: NewInternedStrings
    ) {
        val token = os.start(ViewCaptureMessage.VIEWS)

        os.write(ViewCaptureMessage.View.ID, id)
        os.write(ViewCaptureMessage.View.PARENT_ID, parentId)
        os.write(ViewCaptureMessage.View.HASHCODE, view.hashCode)
        os.write(
            ViewCaptureMessage.View.VIEW_ID_IID,
            internViewId(mViewIdProvider.getName(view.id), incrementalState, newInternedStrings)
        )
        os.write(
            ViewCaptureMessage.View.CLASS_NAME_IID,
            internClassName(view.clazz.name, incrementalState, newInternedStrings)
        )

        os.write(ViewCaptureMessage.View.LEFT, view.left)
        os.write(ViewCaptureMessage.View.TOP, view.top)
        os.write(ViewCaptureMessage.View.WIDTH, view.right - view.left)
        os.write(ViewCaptureMessage.View.HEIGHT, view.bottom - view.top)
        os.write(ViewCaptureMessage.View.SCROLL_X, view.scrollX)
        os.write(ViewCaptureMessage.View.SCROLL_Y, view.scrollY)

        os.write(ViewCaptureMessage.View.TRANSLATION_X, view.translateX)
        os.write(ViewCaptureMessage.View.TRANSLATION_Y, view.translateY)
        os.write(ViewCaptureMessage.View.SCALE_X, view.scaleX)
        os.write(ViewCaptureMessage.View.SCALE_Y, view.scaleY)
        os.write(ViewCaptureMessage.View.ALPHA, view.alpha)

        os.write(ViewCaptureMessage.View.WILL_NOT_DRAW, view.willNotDraw)
        os.write(ViewCaptureMessage.View.CLIP_CHILDREN, view.clipChildren)
        os.write(ViewCaptureMessage.View.VISIBILITY, view.visibility)

        os.write(ViewCaptureMessage.View.ELEVATION, view.elevation)

        os.end(token)
    }

    private fun internClassName(
        string: String,
        incrementalState: ViewCaptureDataSource.IncrementalState,
        newInternedStrings: NewInternedStrings
    ): Int {
        return internString(
            string,
            incrementalState.mInternMapClassName,
            newInternedStrings.classNames
        )
    }

    private fun internPackageName(
        string: String,
        incrementalState: ViewCaptureDataSource.IncrementalState,
        newInternedStrings: NewInternedStrings
    ): Int {
        return internString(
            string,
            incrementalState.mInternMapPackageName,
            newInternedStrings.packageNames
        )
    }

    private fun internViewId(
        string: String,
        incrementalState: ViewCaptureDataSource.IncrementalState,
        newInternedStrings: NewInternedStrings
    ): Int {
        return internString(string, incrementalState.mInternMapViewId, newInternedStrings.viewIds)
    }

    private fun internWindowName(
        string: String,
        incrementalState: ViewCaptureDataSource.IncrementalState,
        newInternedStrings: NewInternedStrings
    ): Int {
        return internString(
            string,
            incrementalState.mInternMapWindowName,
            newInternedStrings.windowNames
        )
    }

    private fun internString(
        string: String,
        internMap: MutableMap<String, Int>,
        newInternedStrings: MutableList<String>
    ): Int {
        if (internMap.containsKey(string)) {
            return internMap[string]!!
        }

        // +1 to avoid intern ID = 0, because javastream optimizes out zero values
        // and the perfetto trace processor would not de-intern that string.
        val internId = internMap.size + 1

        internMap.put(string, internId)
        newInternedStrings.add(string)
        return internId
    }

    private fun serializeIncrementalState(
        os: ProtoOutputStream,
        incrementalState: ViewCaptureDataSource.IncrementalState,
        newInternedStrings: NewInternedStrings
    ) {
        var flags = TracePacket.SEQ_NEEDS_INCREMENTAL_STATE
        if (!incrementalState.mHasNotifiedClearedState) {
            flags = flags or TracePacket.SEQ_INCREMENTAL_STATE_CLEARED
            incrementalState.mHasNotifiedClearedState = true
        }
        os.write(TracePacket.SEQUENCE_FLAGS, flags)

        val token = os.start(TracePacket.INTERNED_DATA)
        serializeInternMap(
            os,
            InternedData.VIEWCAPTURE_CLASS_NAME,
            incrementalState.mInternMapClassName,
            newInternedStrings.classNames
        )
        serializeInternMap(
            os,
            InternedData.VIEWCAPTURE_PACKAGE_NAME,
            incrementalState.mInternMapPackageName,
            newInternedStrings.packageNames
        )
        serializeInternMap(
            os,
            InternedData.VIEWCAPTURE_VIEW_ID,
            incrementalState.mInternMapViewId,
            newInternedStrings.viewIds
        )
        serializeInternMap(
            os,
            InternedData.VIEWCAPTURE_WINDOW_NAME,
            incrementalState.mInternMapWindowName,
            newInternedStrings.windowNames
        )
        os.end(token)
    }

    private fun serializeInternMap(
        os: ProtoOutputStream,
        fieldId: Long,
        map: Map<String, Int>,
        newInternedStrings: List<String>
    ) {
        if (newInternedStrings.isEmpty()) {
            return
        }

        var currentInternId = map.size - newInternedStrings.size + 1
        for (internedString in newInternedStrings) {
            val token = os.start(fieldId)
            os.write(InternedString.IID, currentInternId++)
            os.write(InternedString.STR, internedString.toByteArray())
            os.end(token)
        }
    }

    companion object {
        // Keep two frames in the base class' ring buffer.
        // This is the minimum required by the current implementation to work.
        private val RING_BUFFER_SIZE = 2
    }
}
+13 −3
Original line number Diff line number Diff line
@@ -229,6 +229,10 @@ public abstract class ViewCapture {
                mBgExecutor);
    }

    @WorkerThread
    protected void onCapturedViewPropertiesBg(long elapsedRealtimeNanos, String windowName,
            ViewPropertyRef startFlattenedViewTree) {
    }

    /**
     * Once this window listener is attached to a window's root view, it traverses the entire
@@ -302,7 +306,7 @@ public abstract class ViewCapture {
         */
        @Override
        public void onDraw() {
            Trace.beginSection("view_capture");
            Trace.beginSection("vc#onDraw");
            captureViewTree(mRoot, mViewRef);
            ViewRef captured = mViewRef.next;
            if (captured != null) {
@@ -320,6 +324,8 @@ public abstract class ViewCapture {
         */
        @WorkerThread
        private void captureViewPropertiesBg(ViewRef viewRefStart) {
            Trace.beginSection("vc#captureViewPropertiesBg");

            long elapsedRealtimeNanos = viewRefStart.elapsedRealtimeNanos;
            mFrameIndexBg++;
            if (mFrameIndexBg >= mMemorySize) {
@@ -388,6 +394,10 @@ public abstract class ViewCapture {
                viewRefEnd = viewRefEnd.next;
            }
            mNodesBg[mFrameIndexBg] = resultStart;

            onCapturedViewPropertiesBg(elapsedRealtimeNanos, name, resultStart);

            Trace.endSection();
        }

        private @Nullable ViewPropertyRef findInLastFrame(int hashCode) {
@@ -508,7 +518,7 @@ public abstract class ViewCapture {
        }
    }

    private static class ViewPropertyRef {
    protected static class ViewPropertyRef {
        // We store reference in memory to avoid generating and storing too many strings
        public Class clazz;
        public int hashCode;
@@ -639,7 +649,7 @@ public abstract class ViewCapture {
        }
    }

    private static final class ViewIdProvider {
    protected static final class ViewIdProvider {

        private final SparseArray<String> mNames = new SparseArray<>();
        private final Resources mRes;
Loading