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

Commit 2ede3d62 authored by Sadrul Chowdhury's avatar Sadrul Chowdhury
Browse files

Add 'current animator scale' to ApplicationSharedMemory.

The `getCurrentAnimatorScale()` binder call is on the critical path
during app-launch. On WearOS, the call latency is 7.8ms at p95, and
37ms at p99 (across all pixel devices: 1.4ms and 7ms respectively).
But this information can be shared across all processes (i.e. no
permission checks required), and is simple enough that it can be shared
via ApplicationSharedMemory, and thus avoid this binder call altogether.

Data: go/apc-bl-current-animator-scale

Flag: com.android.window.flags.current_animator_scale_uses_shared_memory
Bug: 406182390
Test: atest ApplicationSharedMemoryTest

Change-Id: I42bee3534336ecef69a1dbde8a42ccb13d9b1e48
parent 09f7681c
Loading
Loading
Loading
Loading
+12 −4
Original line number Original line Diff line number Diff line
@@ -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.PRIVATE_FLAG_OPT_OUT_EDGE_TO_EDGE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;


import static com.android.window.flags.Flags.currentAnimatorScaleUsesSharedMemory;

import android.animation.ValueAnimator;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
@@ -53,6 +55,7 @@ import android.window.WindowContext;


import com.android.internal.R;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.ApplicationSharedMemory;
import com.android.internal.policy.PhoneWindow;
import com.android.internal.policy.PhoneWindow;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastPrintWriter;


@@ -223,16 +226,21 @@ public final class WindowManagerGlobal {
            if (sWindowManagerService == null) {
            if (sWindowManagerService == null) {
                sWindowManagerService = IWindowManager.Stub.asInterface(
                sWindowManagerService = IWindowManager.Stub.asInterface(
                        ServiceManager.getService("window"));
                        ServiceManager.getService("window"));
                try {
                if (currentAnimatorScaleUsesSharedMemory()) {
                    ValueAnimator.setDurationScale(
                            ApplicationSharedMemory.getInstance().getCurrentAnimatorScale());
                } else {
                    // Can be null if this is called before WindowManagerService is initialized.
                    // Can be null if this is called before WindowManagerService is initialized.
                    if (sWindowManagerService != null) {
                    if (sWindowManagerService != null) {
                        try {
                            ValueAnimator.setDurationScale(
                            ValueAnimator.setDurationScale(
                                sWindowManagerService.getCurrentAnimatorScale());
                                sWindowManagerService.getCurrentAnimatorScale());
                    }
                        } catch (RemoteException e) {
                        } catch (RemoteException e) {
                            throw e.rethrowFromSystemServer();
                            throw e.rethrowFromSystemServer();
                        }
                        }
                    }
                    }
                }
            }
            return sWindowManagerService;
            return sWindowManagerService;
        }
        }
    }
    }
+8 −1
Original line number Original line Diff line number Diff line
@@ -509,3 +509,10 @@ flag {
        purpose: PURPOSE_BUGFIX
        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"
}
+20 −0
Original line number Original line Diff line number Diff line
@@ -351,9 +351,29 @@ public class ApplicationSharedMemory implements AutoCloseable {
        return nativeReadSystemFeaturesCache(mPtr);
        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
    @FastNative
    private static native void nativeWriteSystemFeaturesCache(long ptr, int[] cache);
    private static native void nativeWriteSystemFeaturesCache(long ptr, int[] cache);


    @FastNative
    @FastNative
    private static native int[] nativeReadSystemFeaturesCache(long ptr);
    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);
}
}
+38 −3
Original line number Original line Diff line number Diff line
@@ -87,6 +87,9 @@ static_assert(sizeof(SystemFeaturesCache) ==
// Atomics should be safe to use across processes if they are lock free.
// Atomics should be safe to use across processes if they are lock free.
static_assert(std::atomic<int64_t>::is_always_lock_free == true,
static_assert(std::atomic<int64_t>::is_always_lock_free == true,
              "atomic<int64_t> is not always lock free");
              "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.
// This is the data structure that is shared between processes.
//
//
@@ -100,6 +103,7 @@ class alignas(8) SharedMemory { // Ensure that `sizeof(SharedMemory)` is the sam
                                // 64-bit systems.
                                // 64-bit systems.
private:
private:
    volatile std::atomic<int64_t> latestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis;
    volatile std::atomic<int64_t> latestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis;
    volatile std::atomic<float> currentAnimatorScale;


    // LINT.IfChange(invalid_network_time)
    // LINT.IfChange(invalid_network_time)
    static constexpr int64_t INVALID_NETWORK_TIME = -1;
    static constexpr int64_t INVALID_NETWORK_TIME = -1;
@@ -108,7 +112,8 @@ private:
public:
public:
    // Default constructor sets initial values
    // Default constructor sets initial values
    SharedMemory()
    SharedMemory()
          : latestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis(INVALID_NETWORK_TIME) {}
          : latestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis(INVALID_NETWORK_TIME),
            currentAnimatorScale(1.f) {}


    int64_t getLatestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis() const {
    int64_t getLatestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis() const {
        return latestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis;
        return latestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis;
@@ -118,6 +123,14 @@ public:
        latestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis = offset;
        latestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis = offset;
    }
    }


    void setCurrentAnimatorScale(float scale) {
        currentAnimatorScale = scale;
    }

    float getCurrentAnimatorScale() const {
        return currentAnimatorScale;
    }

    // The fixed size cache storage for SDK-defined system features.
    // The fixed size cache storage for SDK-defined system features.
    SystemFeaturesCache systemFeaturesCache;
    SystemFeaturesCache systemFeaturesCache;


@@ -130,9 +143,19 @@ public:
// and 64-bit systems.
// and 64-bit systems.
// TODO(b/396674280): Add an additional fixed size check for SystemCacheNonce after resolving
// TODO(b/396674280): Add an additional fixed size check for SystemCacheNonce after resolving
// ABI discrepancies.
// 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");
              "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");
              "Unexpected SystemFeaturesCache offset in SharedMemory");
static_assert(offsetof(SharedMemory, systemPic) ==
static_assert(offsetof(SharedMemory, systemPic) ==
                      offsetof(SharedMemory, systemFeaturesCache) + sizeof(SystemFeaturesCache),
                      offsetof(SharedMemory, systemFeaturesCache) + sizeof(SystemFeaturesCache),
@@ -216,6 +239,16 @@ static jintArray nativeReadSystemFeaturesCache(JNIEnv* env, jclass*, jlong ptr)
    return sharedMemory->systemFeaturesCache.readSystemFeatures(env);
    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[] = {
static const JNINativeMethod gMethods[] = {
        {"nativeCreate", "()I", (void*)nativeCreate},
        {"nativeCreate", "()I", (void*)nativeCreate},
        {"nativeMap", "(IZ)J", (void*)nativeMap},
        {"nativeMap", "(IZ)J", (void*)nativeMap},
@@ -229,6 +262,8 @@ static const JNINativeMethod gMethods[] = {
        {"nativeGetSystemNonceBlock", "(J)J", (void*)nativeGetSystemNonceBlock},
        {"nativeGetSystemNonceBlock", "(J)J", (void*)nativeGetSystemNonceBlock},
        {"nativeWriteSystemFeaturesCache", "(J[I)V", (void*)nativeWriteSystemFeaturesCache},
        {"nativeWriteSystemFeaturesCache", "(J[I)V", (void*)nativeWriteSystemFeaturesCache},
        {"nativeReadSystemFeaturesCache", "(J)[I", (void*)nativeReadSystemFeaturesCache},
        {"nativeReadSystemFeaturesCache", "(J)[I", (void*)nativeReadSystemFeaturesCache},
        {"nativeSetCurrentAnimatorScale", "(JF)V", (void*)nativeSetCurrentAnimatorScale},
        {"nativeGetCurrentAnimatorScale", "(J)F", (void*)nativeGetCurrentAnimatorScale},
};
};


static const char kApplicationSharedMemoryClassName[] =
static const char kApplicationSharedMemoryClassName[] =
+69 −0
Original line number Original line 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