Loading packages/SystemUI/shared/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ android_library { "SystemUIPluginLib", "SystemUIUnfoldLib", "SystemUISharedLib-Keyguard", "tracinglib", "androidx.dynamicanimation_dynamicanimation", "androidx.concurrent_concurrent-futures", "androidx.lifecycle_lifecycle-runtime-ktx", Loading packages/SystemUI/shared/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListener.kt +1 −1 Original line number Diff line number Diff line Loading @@ -19,7 +19,7 @@ import android.graphics.Paint import android.view.ViewGroup import android.widget.TextView import androidx.core.view.forEach import com.android.systemui.tracing.traceSection import com.android.app.tracing.traceSection import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener import java.lang.ref.WeakReference Loading packages/SystemUI/shared/src/com/android/systemui/tracing/TraceContextElement.ktdeleted 100644 → 0 +0 −69 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.systemui.tracing import com.android.systemui.tracing.TraceUtils.Companion.instant import com.android.systemui.tracing.TraceUtils.Companion.traceCoroutine import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.CopyableThreadContextElement import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi /** * Used for safely persisting [TraceData] state when coroutines are suspended and resumed. * * This is internal machinery for [traceCoroutine]. It cannot be made `internal` or `private` * because [traceCoroutine] is a Public-API inline function. * * @see traceCoroutine */ @OptIn(DelicateCoroutinesApi::class) @ExperimentalCoroutinesApi class TraceContextElement(private val traceData: TraceData = TraceData()) : CopyableThreadContextElement<TraceData?> { companion object Key : CoroutineContext.Key<TraceContextElement> override val key: CoroutineContext.Key<TraceContextElement> = Key @OptIn(ExperimentalStdlibApi::class) override fun updateThreadContext(context: CoroutineContext): TraceData? { val oldState = threadLocalTrace.get() oldState?.endAllOnThread() threadLocalTrace.set(traceData) instant("resuming ${context[CoroutineDispatcher]}") traceData.beginAllOnThread() return oldState } @OptIn(ExperimentalStdlibApi::class) override fun restoreThreadContext(context: CoroutineContext, oldState: TraceData?) { instant("suspending ${context[CoroutineDispatcher]}") traceData.endAllOnThread() threadLocalTrace.set(oldState) oldState?.beginAllOnThread() } override fun copyForChild(): CopyableThreadContextElement<TraceData?> { return TraceContextElement(traceData.copy()) } override fun mergeForChild(overwritingElement: CoroutineContext.Element): CoroutineContext { return TraceContextElement(traceData.copy()) } } packages/SystemUI/shared/src/com/android/systemui/tracing/TraceData.ktdeleted 100644 → 0 +0 −122 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.systemui.tracing import android.os.Build import android.util.Log import com.android.systemui.tracing.TraceUtils.Companion.beginSlice import com.android.systemui.tracing.TraceUtils.Companion.endSlice import com.android.systemui.tracing.TraceUtils.Companion.traceCoroutine import kotlin.random.Random /** * Used for giving each thread a unique [TraceData] for thread-local storage. `null` by default. * [threadLocalTrace] can only be used when it is paired with a [TraceContextElement]. * * This ThreadLocal will be `null` if either 1) we aren't in a coroutine, or 2) the coroutine we are * in does not have a [TraceContextElement]. * * This is internal machinery for [traceCoroutine]. It cannot be made `internal` or `private` * because [traceCoroutine] is a Public-API inline function. * * @see traceCoroutine */ val threadLocalTrace = ThreadLocal<TraceData?>() /** * Used for storing trace sections so that they can be added and removed from the currently running * thread when the coroutine is suspended and resumed. * * This is internal machinery for [traceCoroutine]. It cannot be made `internal` or `private` * because [traceCoroutine] is a Public-API inline function. * * @see traceCoroutine */ class TraceData { private var slices = mutableListOf<TraceSection>() /** Adds current trace slices back to the current thread. Called when coroutine is resumed. */ fun beginAllOnThread() { slices.forEach { beginSlice(it.name) } } /** * Removes all current trace slices from the current thread. Called when coroutine is suspended. */ fun endAllOnThread() { for (i in 0..slices.size) { endSlice() } } /** * Creates a new trace section with a unique ID and adds it to the current trace data. The slice * will also be added to the current thread immediately. This slice will not propagate to parent * coroutines, or to child coroutines that have already started. The unique ID is used to verify * that the [endSpan] is corresponds to a [beginSpan]. */ fun beginSpan(name: String): Int { val newSlice = TraceSection(name, Random.nextInt(FIRST_VALID_SPAN, Int.MAX_VALUE)) slices.add(newSlice) beginSlice(name) return newSlice.id } /** * Used by [TraceContextElement] when launching a child coroutine so that the child coroutine's * state is isolated from the parent. */ fun copy(): TraceData { return TraceData().also { it.slices.addAll(slices) } } /** * Ends the trace section and validates it corresponds with an earlier call to [beginSpan]. The * trace slice will immediately be removed from the current thread. This information will not * propagate to parent coroutines, or to child coroutines that have already started. */ fun endSpan(id: Int) { val v = slices.removeLast() if (v.id != id) { if (STRICT_MODE) { throw IllegalArgumentException(errorMsg) } else if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, errorMsg) } } endSlice() } companion object { private const val TAG = "TraceData" const val INVALID_SPAN = -1 const val FIRST_VALID_SPAN = 1 /** * If true, throw an exception instead of printing a warning when trace sections beginnings * and ends are mismatched. */ private val STRICT_MODE = Build.IS_ENG private const val errorMsg = "Mismatched trace section. This likely means you are accessing the trace local " + "storage (threadLocalTrace) without a corresponding CopyableThreadContextElement." + " This could happen if you are using a global dispatcher like Dispatchers.IO." + " To fix this, use one of the coroutine contexts provided by the dagger scope " + "(e.g. \"@Main CoroutineContext\")." } } packages/SystemUI/shared/src/com/android/systemui/tracing/TraceSection.ktdeleted 100644 → 0 +0 −35 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.systemui.tracing import com.android.systemui.tracing.TraceUtils.Companion.traceCoroutine /** * Represents a section of code executing in a coroutine. This can be split up into multiple slices * on different threads as the coroutine is suspended and resumed. * * This is internal machinery for [traceCoroutine]. It cannot be made `internal` or `private` * because [traceCoroutine] is a Public-API inline function. * * @param name the name of the slice to appear on the current thread's track. * @param id used for matching the beginning and end of trace sections and validating correctness * @see traceCoroutine */ data class TraceSection( val name: String, val id: Int, ) Loading
packages/SystemUI/shared/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ android_library { "SystemUIPluginLib", "SystemUIUnfoldLib", "SystemUISharedLib-Keyguard", "tracinglib", "androidx.dynamicanimation_dynamicanimation", "androidx.concurrent_concurrent-futures", "androidx.lifecycle_lifecycle-runtime-ktx", Loading
packages/SystemUI/shared/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListener.kt +1 −1 Original line number Diff line number Diff line Loading @@ -19,7 +19,7 @@ import android.graphics.Paint import android.view.ViewGroup import android.widget.TextView import androidx.core.view.forEach import com.android.systemui.tracing.traceSection import com.android.app.tracing.traceSection import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener import java.lang.ref.WeakReference Loading
packages/SystemUI/shared/src/com/android/systemui/tracing/TraceContextElement.ktdeleted 100644 → 0 +0 −69 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.systemui.tracing import com.android.systemui.tracing.TraceUtils.Companion.instant import com.android.systemui.tracing.TraceUtils.Companion.traceCoroutine import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.CopyableThreadContextElement import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi /** * Used for safely persisting [TraceData] state when coroutines are suspended and resumed. * * This is internal machinery for [traceCoroutine]. It cannot be made `internal` or `private` * because [traceCoroutine] is a Public-API inline function. * * @see traceCoroutine */ @OptIn(DelicateCoroutinesApi::class) @ExperimentalCoroutinesApi class TraceContextElement(private val traceData: TraceData = TraceData()) : CopyableThreadContextElement<TraceData?> { companion object Key : CoroutineContext.Key<TraceContextElement> override val key: CoroutineContext.Key<TraceContextElement> = Key @OptIn(ExperimentalStdlibApi::class) override fun updateThreadContext(context: CoroutineContext): TraceData? { val oldState = threadLocalTrace.get() oldState?.endAllOnThread() threadLocalTrace.set(traceData) instant("resuming ${context[CoroutineDispatcher]}") traceData.beginAllOnThread() return oldState } @OptIn(ExperimentalStdlibApi::class) override fun restoreThreadContext(context: CoroutineContext, oldState: TraceData?) { instant("suspending ${context[CoroutineDispatcher]}") traceData.endAllOnThread() threadLocalTrace.set(oldState) oldState?.beginAllOnThread() } override fun copyForChild(): CopyableThreadContextElement<TraceData?> { return TraceContextElement(traceData.copy()) } override fun mergeForChild(overwritingElement: CoroutineContext.Element): CoroutineContext { return TraceContextElement(traceData.copy()) } }
packages/SystemUI/shared/src/com/android/systemui/tracing/TraceData.ktdeleted 100644 → 0 +0 −122 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.systemui.tracing import android.os.Build import android.util.Log import com.android.systemui.tracing.TraceUtils.Companion.beginSlice import com.android.systemui.tracing.TraceUtils.Companion.endSlice import com.android.systemui.tracing.TraceUtils.Companion.traceCoroutine import kotlin.random.Random /** * Used for giving each thread a unique [TraceData] for thread-local storage. `null` by default. * [threadLocalTrace] can only be used when it is paired with a [TraceContextElement]. * * This ThreadLocal will be `null` if either 1) we aren't in a coroutine, or 2) the coroutine we are * in does not have a [TraceContextElement]. * * This is internal machinery for [traceCoroutine]. It cannot be made `internal` or `private` * because [traceCoroutine] is a Public-API inline function. * * @see traceCoroutine */ val threadLocalTrace = ThreadLocal<TraceData?>() /** * Used for storing trace sections so that they can be added and removed from the currently running * thread when the coroutine is suspended and resumed. * * This is internal machinery for [traceCoroutine]. It cannot be made `internal` or `private` * because [traceCoroutine] is a Public-API inline function. * * @see traceCoroutine */ class TraceData { private var slices = mutableListOf<TraceSection>() /** Adds current trace slices back to the current thread. Called when coroutine is resumed. */ fun beginAllOnThread() { slices.forEach { beginSlice(it.name) } } /** * Removes all current trace slices from the current thread. Called when coroutine is suspended. */ fun endAllOnThread() { for (i in 0..slices.size) { endSlice() } } /** * Creates a new trace section with a unique ID and adds it to the current trace data. The slice * will also be added to the current thread immediately. This slice will not propagate to parent * coroutines, or to child coroutines that have already started. The unique ID is used to verify * that the [endSpan] is corresponds to a [beginSpan]. */ fun beginSpan(name: String): Int { val newSlice = TraceSection(name, Random.nextInt(FIRST_VALID_SPAN, Int.MAX_VALUE)) slices.add(newSlice) beginSlice(name) return newSlice.id } /** * Used by [TraceContextElement] when launching a child coroutine so that the child coroutine's * state is isolated from the parent. */ fun copy(): TraceData { return TraceData().also { it.slices.addAll(slices) } } /** * Ends the trace section and validates it corresponds with an earlier call to [beginSpan]. The * trace slice will immediately be removed from the current thread. This information will not * propagate to parent coroutines, or to child coroutines that have already started. */ fun endSpan(id: Int) { val v = slices.removeLast() if (v.id != id) { if (STRICT_MODE) { throw IllegalArgumentException(errorMsg) } else if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, errorMsg) } } endSlice() } companion object { private const val TAG = "TraceData" const val INVALID_SPAN = -1 const val FIRST_VALID_SPAN = 1 /** * If true, throw an exception instead of printing a warning when trace sections beginnings * and ends are mismatched. */ private val STRICT_MODE = Build.IS_ENG private const val errorMsg = "Mismatched trace section. This likely means you are accessing the trace local " + "storage (threadLocalTrace) without a corresponding CopyableThreadContextElement." + " This could happen if you are using a global dispatcher like Dispatchers.IO." + " To fix this, use one of the coroutine contexts provided by the dagger scope " + "(e.g. \"@Main CoroutineContext\")." } }
packages/SystemUI/shared/src/com/android/systemui/tracing/TraceSection.ktdeleted 100644 → 0 +0 −35 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.systemui.tracing import com.android.systemui.tracing.TraceUtils.Companion.traceCoroutine /** * Represents a section of code executing in a coroutine. This can be split up into multiple slices * on different threads as the coroutine is suspended and resumed. * * This is internal machinery for [traceCoroutine]. It cannot be made `internal` or `private` * because [traceCoroutine] is a Public-API inline function. * * @param name the name of the slice to appear on the current thread's track. * @param id used for matching the beginning and end of trace sections and validating correctness * @see traceCoroutine */ data class TraceSection( val name: String, val id: Int, )