Loading core/java/android/view/WindowManagerGlobal.java +12 −4 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPT_OUT_EDGE_TO_EDGE; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static com.android.window.flags.Flags.currentAnimatorScaleUsesSharedMemory; import android.animation.ValueAnimator; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -53,6 +55,7 @@ import android.window.WindowContext; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.ApplicationSharedMemory; import com.android.internal.policy.PhoneWindow; import com.android.internal.util.FastPrintWriter; Loading Loading @@ -223,16 +226,21 @@ public final class WindowManagerGlobal { if (sWindowManagerService == null) { sWindowManagerService = IWindowManager.Stub.asInterface( ServiceManager.getService("window")); try { if (currentAnimatorScaleUsesSharedMemory()) { ValueAnimator.setDurationScale( ApplicationSharedMemory.getInstance().getCurrentAnimatorScale()); } else { // Can be null if this is called before WindowManagerService is initialized. if (sWindowManagerService != null) { try { ValueAnimator.setDurationScale( sWindowManagerService.getCurrentAnimatorScale()); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } } return sWindowManagerService; } } Loading core/java/android/window/flags/windowing_frontend.aconfig +8 −1 Original line number Diff line number Diff line Loading @@ -509,3 +509,10 @@ flag { purpose: PURPOSE_BUGFIX } } flag { name: "current_animator_scale_uses_shared_memory" namespace: "wear_system_health" description: "WindowManagerService.getCurrentAnimatorScale() reads the animator scale from shared memory" bug: "406182390" } core/java/com/android/internal/os/ApplicationSharedMemory.java +20 −0 Original line number Diff line number Diff line Loading @@ -351,9 +351,29 @@ public class ApplicationSharedMemory implements AutoCloseable { return nativeReadSystemFeaturesCache(mPtr); } /** Sets the current animator scale from the WindowManagerService. */ public void setCurrentAnimatorScale(float scale) { checkMutable(); nativeSetCurrentAnimatorScale(mPtr, scale); } /** Returns the current animator scale set by the WindowManagerService. */ public float getCurrentAnimatorScale() { checkMapped(); return nativeGetCurrentAnimatorScale(mPtr); } @FastNative private static native void nativeWriteSystemFeaturesCache(long ptr, int[] cache); @FastNative private static native int[] nativeReadSystemFeaturesCache(long ptr); @FastNative private static native void nativeSetCurrentAnimatorScale(long ptr, float scale); @FastNative private static native float nativeGetCurrentAnimatorScale(long ptr); } core/jni/com_android_internal_os_ApplicationSharedMemory.cpp +38 −3 Original line number Diff line number Diff line Loading @@ -87,6 +87,9 @@ static_assert(sizeof(SystemFeaturesCache) == // Atomics should be safe to use across processes if they are lock free. static_assert(std::atomic<int64_t>::is_always_lock_free == true, "atomic<int64_t> is not always lock free"); // Atomics should be safe to use across processes if they are lock free. static_assert(std::atomic<float>::is_always_lock_free == true, "atomic<float> is not always lock free"); // This is the data structure that is shared between processes. // Loading @@ -100,6 +103,7 @@ class alignas(8) SharedMemory { // Ensure that `sizeof(SharedMemory)` is the sam // 64-bit systems. private: volatile std::atomic<int64_t> latestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis; volatile std::atomic<float> currentAnimatorScale; // LINT.IfChange(invalid_network_time) static constexpr int64_t INVALID_NETWORK_TIME = -1; Loading @@ -108,7 +112,8 @@ private: public: // Default constructor sets initial values SharedMemory() : latestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis(INVALID_NETWORK_TIME) {} : latestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis(INVALID_NETWORK_TIME), currentAnimatorScale(1.f) {} int64_t getLatestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis() const { return latestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis; Loading @@ -118,6 +123,14 @@ public: latestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis = offset; } void setCurrentAnimatorScale(float scale) { currentAnimatorScale = scale; } float getCurrentAnimatorScale() const { return currentAnimatorScale; } // The fixed size cache storage for SDK-defined system features. SystemFeaturesCache systemFeaturesCache; Loading @@ -130,9 +143,19 @@ public: // and 64-bit systems. // TODO(b/396674280): Add an additional fixed size check for SystemCacheNonce after resolving // ABI discrepancies. static_assert(sizeof(SharedMemory) == 8 + sizeof(SystemFeaturesCache) + sizeof(SystemCacheNonce), static_assert(sizeof(SharedMemory) == // latestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis 8 + // currentAnimatorScale 8 + sizeof(SystemFeaturesCache) + sizeof(SystemCacheNonce), "Unexpected SharedMemory size"); static_assert(offsetof(SharedMemory, systemFeaturesCache) == sizeof(int64_t), static_assert(offsetof(SharedMemory, systemFeaturesCache) == // latestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis 8 + // currentAnimatorScale 8, "Unexpected SystemFeaturesCache offset in SharedMemory"); static_assert(offsetof(SharedMemory, systemPic) == offsetof(SharedMemory, systemFeaturesCache) + sizeof(SystemFeaturesCache), Loading Loading @@ -216,6 +239,16 @@ static jintArray nativeReadSystemFeaturesCache(JNIEnv* env, jclass*, jlong ptr) return sharedMemory->systemFeaturesCache.readSystemFeatures(env); } static void nativeSetCurrentAnimatorScale(JNIEnv* env, jclass*, jlong ptr, jfloat scale) { SharedMemory* sharedMemory = reinterpret_cast<SharedMemory*>(ptr); sharedMemory->setCurrentAnimatorScale(scale); } static jfloat nativeGetCurrentAnimatorScale(JNIEnv* env, jclass*, jlong ptr) { SharedMemory* sharedMemory = reinterpret_cast<SharedMemory*>(ptr); return sharedMemory->getCurrentAnimatorScale(); } static const JNINativeMethod gMethods[] = { {"nativeCreate", "()I", (void*)nativeCreate}, {"nativeMap", "(IZ)J", (void*)nativeMap}, Loading @@ -229,6 +262,8 @@ static const JNINativeMethod gMethods[] = { {"nativeGetSystemNonceBlock", "(J)J", (void*)nativeGetSystemNonceBlock}, {"nativeWriteSystemFeaturesCache", "(J[I)V", (void*)nativeWriteSystemFeaturesCache}, {"nativeReadSystemFeaturesCache", "(J)[I", (void*)nativeReadSystemFeaturesCache}, {"nativeSetCurrentAnimatorScale", "(JF)V", (void*)nativeSetCurrentAnimatorScale}, {"nativeGetCurrentAnimatorScale", "(J)F", (void*)nativeGetCurrentAnimatorScale}, }; static const char kApplicationSharedMemoryClassName[] = Loading services/core/java/com/android/server/wm/SharedMemoryBackedCurrentAnimatorScale.java 0 → 100644 +69 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.server.wm; import static com.android.window.flags.Flags.currentAnimatorScaleUsesSharedMemory; import com.android.internal.os.ApplicationSharedMemory; /** * Uses ApplicationSharedMemory to update the animator scale. * * This helps apps avoid an unnecessary binder call to get the animator scale, since the information * is stored in shared memory. */ final class SharedMemoryBackedCurrentAnimatorScale { private boolean mAnimationsDisabled = false; private float mCurrentAnimatorScale = 1.f; SharedMemoryBackedCurrentAnimatorScale() { updateSharedMemoryValue(); } void setAnimationsDisabled(boolean disabled) { if (mAnimationsDisabled == disabled) { return; } mAnimationsDisabled = disabled; updateSharedMemoryValue(); } void setCurrentScale(float scale) { if (mCurrentAnimatorScale == scale) { return; } mCurrentAnimatorScale = scale; updateSharedMemoryValue(); } float getCurrentScale() { return mAnimationsDisabled ? 0 : mCurrentAnimatorScale; } boolean isAnimationsDisabled() { return mAnimationsDisabled; } private void updateSharedMemoryValue() { if (currentAnimatorScaleUsesSharedMemory()) { ApplicationSharedMemory.getInstance().setCurrentAnimatorScale( getCurrentScale()); } } }; Loading
core/java/android/view/WindowManagerGlobal.java +12 −4 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPT_OUT_EDGE_TO_EDGE; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static com.android.window.flags.Flags.currentAnimatorScaleUsesSharedMemory; import android.animation.ValueAnimator; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -53,6 +55,7 @@ import android.window.WindowContext; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.ApplicationSharedMemory; import com.android.internal.policy.PhoneWindow; import com.android.internal.util.FastPrintWriter; Loading Loading @@ -223,16 +226,21 @@ public final class WindowManagerGlobal { if (sWindowManagerService == null) { sWindowManagerService = IWindowManager.Stub.asInterface( ServiceManager.getService("window")); try { if (currentAnimatorScaleUsesSharedMemory()) { ValueAnimator.setDurationScale( ApplicationSharedMemory.getInstance().getCurrentAnimatorScale()); } else { // Can be null if this is called before WindowManagerService is initialized. if (sWindowManagerService != null) { try { ValueAnimator.setDurationScale( sWindowManagerService.getCurrentAnimatorScale()); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } } return sWindowManagerService; } } Loading
core/java/android/window/flags/windowing_frontend.aconfig +8 −1 Original line number Diff line number Diff line Loading @@ -509,3 +509,10 @@ flag { purpose: PURPOSE_BUGFIX } } flag { name: "current_animator_scale_uses_shared_memory" namespace: "wear_system_health" description: "WindowManagerService.getCurrentAnimatorScale() reads the animator scale from shared memory" bug: "406182390" }
core/java/com/android/internal/os/ApplicationSharedMemory.java +20 −0 Original line number Diff line number Diff line Loading @@ -351,9 +351,29 @@ public class ApplicationSharedMemory implements AutoCloseable { return nativeReadSystemFeaturesCache(mPtr); } /** Sets the current animator scale from the WindowManagerService. */ public void setCurrentAnimatorScale(float scale) { checkMutable(); nativeSetCurrentAnimatorScale(mPtr, scale); } /** Returns the current animator scale set by the WindowManagerService. */ public float getCurrentAnimatorScale() { checkMapped(); return nativeGetCurrentAnimatorScale(mPtr); } @FastNative private static native void nativeWriteSystemFeaturesCache(long ptr, int[] cache); @FastNative private static native int[] nativeReadSystemFeaturesCache(long ptr); @FastNative private static native void nativeSetCurrentAnimatorScale(long ptr, float scale); @FastNative private static native float nativeGetCurrentAnimatorScale(long ptr); }
core/jni/com_android_internal_os_ApplicationSharedMemory.cpp +38 −3 Original line number Diff line number Diff line Loading @@ -87,6 +87,9 @@ static_assert(sizeof(SystemFeaturesCache) == // Atomics should be safe to use across processes if they are lock free. static_assert(std::atomic<int64_t>::is_always_lock_free == true, "atomic<int64_t> is not always lock free"); // Atomics should be safe to use across processes if they are lock free. static_assert(std::atomic<float>::is_always_lock_free == true, "atomic<float> is not always lock free"); // This is the data structure that is shared between processes. // Loading @@ -100,6 +103,7 @@ class alignas(8) SharedMemory { // Ensure that `sizeof(SharedMemory)` is the sam // 64-bit systems. private: volatile std::atomic<int64_t> latestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis; volatile std::atomic<float> currentAnimatorScale; // LINT.IfChange(invalid_network_time) static constexpr int64_t INVALID_NETWORK_TIME = -1; Loading @@ -108,7 +112,8 @@ private: public: // Default constructor sets initial values SharedMemory() : latestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis(INVALID_NETWORK_TIME) {} : latestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis(INVALID_NETWORK_TIME), currentAnimatorScale(1.f) {} int64_t getLatestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis() const { return latestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis; Loading @@ -118,6 +123,14 @@ public: latestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis = offset; } void setCurrentAnimatorScale(float scale) { currentAnimatorScale = scale; } float getCurrentAnimatorScale() const { return currentAnimatorScale; } // The fixed size cache storage for SDK-defined system features. SystemFeaturesCache systemFeaturesCache; Loading @@ -130,9 +143,19 @@ public: // and 64-bit systems. // TODO(b/396674280): Add an additional fixed size check for SystemCacheNonce after resolving // ABI discrepancies. static_assert(sizeof(SharedMemory) == 8 + sizeof(SystemFeaturesCache) + sizeof(SystemCacheNonce), static_assert(sizeof(SharedMemory) == // latestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis 8 + // currentAnimatorScale 8 + sizeof(SystemFeaturesCache) + sizeof(SystemCacheNonce), "Unexpected SharedMemory size"); static_assert(offsetof(SharedMemory, systemFeaturesCache) == sizeof(int64_t), static_assert(offsetof(SharedMemory, systemFeaturesCache) == // latestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis 8 + // currentAnimatorScale 8, "Unexpected SystemFeaturesCache offset in SharedMemory"); static_assert(offsetof(SharedMemory, systemPic) == offsetof(SharedMemory, systemFeaturesCache) + sizeof(SystemFeaturesCache), Loading Loading @@ -216,6 +239,16 @@ static jintArray nativeReadSystemFeaturesCache(JNIEnv* env, jclass*, jlong ptr) return sharedMemory->systemFeaturesCache.readSystemFeatures(env); } static void nativeSetCurrentAnimatorScale(JNIEnv* env, jclass*, jlong ptr, jfloat scale) { SharedMemory* sharedMemory = reinterpret_cast<SharedMemory*>(ptr); sharedMemory->setCurrentAnimatorScale(scale); } static jfloat nativeGetCurrentAnimatorScale(JNIEnv* env, jclass*, jlong ptr) { SharedMemory* sharedMemory = reinterpret_cast<SharedMemory*>(ptr); return sharedMemory->getCurrentAnimatorScale(); } static const JNINativeMethod gMethods[] = { {"nativeCreate", "()I", (void*)nativeCreate}, {"nativeMap", "(IZ)J", (void*)nativeMap}, Loading @@ -229,6 +262,8 @@ static const JNINativeMethod gMethods[] = { {"nativeGetSystemNonceBlock", "(J)J", (void*)nativeGetSystemNonceBlock}, {"nativeWriteSystemFeaturesCache", "(J[I)V", (void*)nativeWriteSystemFeaturesCache}, {"nativeReadSystemFeaturesCache", "(J)[I", (void*)nativeReadSystemFeaturesCache}, {"nativeSetCurrentAnimatorScale", "(JF)V", (void*)nativeSetCurrentAnimatorScale}, {"nativeGetCurrentAnimatorScale", "(J)F", (void*)nativeGetCurrentAnimatorScale}, }; static const char kApplicationSharedMemoryClassName[] = Loading
services/core/java/com/android/server/wm/SharedMemoryBackedCurrentAnimatorScale.java 0 → 100644 +69 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.server.wm; import static com.android.window.flags.Flags.currentAnimatorScaleUsesSharedMemory; import com.android.internal.os.ApplicationSharedMemory; /** * Uses ApplicationSharedMemory to update the animator scale. * * This helps apps avoid an unnecessary binder call to get the animator scale, since the information * is stored in shared memory. */ final class SharedMemoryBackedCurrentAnimatorScale { private boolean mAnimationsDisabled = false; private float mCurrentAnimatorScale = 1.f; SharedMemoryBackedCurrentAnimatorScale() { updateSharedMemoryValue(); } void setAnimationsDisabled(boolean disabled) { if (mAnimationsDisabled == disabled) { return; } mAnimationsDisabled = disabled; updateSharedMemoryValue(); } void setCurrentScale(float scale) { if (mCurrentAnimatorScale == scale) { return; } mCurrentAnimatorScale = scale; updateSharedMemoryValue(); } float getCurrentScale() { return mAnimationsDisabled ? 0 : mCurrentAnimatorScale; } boolean isAnimationsDisabled() { return mAnimationsDisabled; } private void updateSharedMemoryValue() { if (currentAnimatorScaleUsesSharedMemory()) { ApplicationSharedMemory.getInstance().setCurrentAnimatorScale( getCurrentScale()); } } };