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

Commit fceee1f0 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Changes to VibrationThread in preparation for sessions" into main

parents 340a1b19 936a4d9d
Loading
Loading
Loading
Loading
+13 −6
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.vibrator;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.os.ExternalVibration;
@@ -24,6 +25,7 @@ import android.os.IBinder;
import android.os.VibrationAttributes;
import android.os.vibrator.Flags;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.FrameworkStatsLog;

/**
@@ -32,14 +34,16 @@ import com.android.internal.util.FrameworkStatsLog;
final class ExternalVibrationSession extends Vibration
        implements VibrationSession, IBinder.DeathRecipient {

    private final Object mLock = new Object();
    private final ExternalVibration mExternalVibration;
    private final ExternalVibrationScale mScale = new ExternalVibrationScale();

    @GuardedBy("mLock")
    @Nullable
    private Runnable mBinderDeathCallback;

    ExternalVibrationSession(ExternalVibration externalVibration) {
        super(externalVibration.getToken(), new CallerInfo(
        super(new CallerInfo(
                externalVibration.getVibrationAttributes(), externalVibration.getUid(),
                // TODO(b/249785241): Find a way to link ExternalVibration to a VirtualDevice
                // instead of using DEVICE_ID_INVALID here and relying on the UID checks.
@@ -82,24 +86,25 @@ final class ExternalVibrationSession extends Vibration
    }

    @Override
    public void linkToDeath(Runnable callback) {
        synchronized (this) {
    public boolean linkToDeath(Runnable callback) {
        synchronized (mLock) {
            mBinderDeathCallback = callback;
        }
        mExternalVibration.linkToDeath(this);
        return true;
    }

    @Override
    public void unlinkToDeath() {
        mExternalVibration.unlinkToDeath(this);
        synchronized (this) {
        synchronized (mLock) {
            mBinderDeathCallback = null;
        }
    }

    @Override
    public void binderDied() {
        synchronized (this) {
        synchronized (mLock) {
            if (mBinderDeathCallback != null) {
                mBinderDeathCallback.run();
            }
@@ -119,9 +124,11 @@ final class ExternalVibrationSession extends Vibration
    }

    @Override
    public void notifyEnded() {
    public void requestEnd(@NonNull Status status, @Nullable CallerInfo endedBy,
            boolean immediate) {
        // Notify external client that this vibration should stop sending data to the vibrator.
        mExternalVibration.mute();
        end(new EndInfo(status, endedBy));
    }

    boolean isHoldingSameVibration(ExternalVibration vib) {
+4 −2
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import java.util.concurrent.CountDownLatch;
final class HalVibration extends Vibration {

    public final SparseArray<VibrationEffect> mFallbacks = new SparseArray<>();
    public final IBinder callerToken;

    /** A {@link CountDownLatch} to enable waiting for completion. */
    private final CountDownLatch mCompletionLatch = new CountDownLatch(1);
@@ -55,9 +56,10 @@ final class HalVibration extends Vibration {
    private int mScaleLevel;
    private float mAdaptiveScale;

    HalVibration(@NonNull IBinder token, @NonNull CombinedVibration effect,
    HalVibration(@NonNull IBinder callerToken, @NonNull CombinedVibration effect,
            @NonNull VibrationSession.CallerInfo callerInfo) {
        super(token, callerInfo);
        super(callerInfo);
        this.callerToken = callerToken;
        mOriginalEffect = effect;
        mEffectToPlay = effect;
        mScaleLevel = VibrationScaler.SCALE_NONE;
+1 −4
Original line number Diff line number Diff line
@@ -53,16 +53,13 @@ abstract class Vibration {
    public final long id;
    public final VibrationSession.CallerInfo callerInfo;
    public final VibrationStats stats = new VibrationStats();
    public final IBinder callerToken;

    private VibrationSession.Status mStatus;

    Vibration(@NonNull IBinder token, @NonNull VibrationSession.CallerInfo callerInfo) {
        Objects.requireNonNull(token);
    Vibration(@NonNull VibrationSession.CallerInfo callerInfo) {
        Objects.requireNonNull(callerInfo);
        mStatus = VibrationSession.Status.RUNNING;
        this.id = sNextVibrationId.getAndIncrement();
        this.callerToken = token;
        this.callerInfo = callerInfo;
    }

+16 −4
Original line number Diff line number Diff line
@@ -49,14 +49,26 @@ interface VibrationSession {
     * Links this session to the app process death with given callback to handle it.
     *
     * <p>This can be used by the service to end the vibration session when the app process dies.
     *
     * @param callback The service callback to be triggered when the binder dies
     * @return true if the link was successful, false otherwise
     */
    void linkToDeath(Runnable callback);
    boolean linkToDeath(@Nullable Runnable callback);

    /** Removes link to the app process death. */
    void unlinkToDeath();

    /** Notify the session end was requested, which might be acted upon asynchronously. */
    void notifyEnded();
    /**
     * Notify the session end was requested, which might be acted upon asynchronously.
     *
     * <p>Only the first end signal will be used to end a session, but subsequent calls with
     * {@code immediate} flag set to true can still force it to take effect urgently.
     *
     * @param status the end status.
     * @param endedBy the {@link CallerInfo} of the session that requested this session to end.
     * @param immediate indicates whether cancellation should abort urgently and skip cleanup steps.
     */
    void requestEnd(@NonNull Status status, @Nullable CallerInfo endedBy, boolean immediate);

    /**
     * Session status with reference to values from vibratormanagerservice.proto for logging.
@@ -119,7 +131,7 @@ interface VibrationSession {
        public final String reason;

        CallerInfo(@NonNull VibrationAttributes attrs, int uid, int deviceId, String opPkg,
                String reason) {
                @Nullable String reason) {
            Objects.requireNonNull(attrs);
            this.attrs = attrs;
            this.uid = uid;
+41 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.os.Build;
import android.os.CombinedVibration;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.VibrationEffect;
import android.os.vibrator.Flags;
import android.os.vibrator.PrebakedSegment;
@@ -38,6 +39,7 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.concurrent.CancellationException;
@@ -357,6 +359,28 @@ final class VibrationStepConductor implements IBinder.DeathRecipient {
                /* immediate= */ false);
    }

    /**
     * Returns true if successfully linked this conductor to the death of the binder that requested
     * the vibration.
     */
    public boolean linkToDeath() {
        try {
            mVibration.callerToken.linkToDeath(this, 0);
        } catch (RemoteException e) {
            Slog.e(TAG, "Error linking vibration to token death", e);
            return false;
        }
        return true;
    }

    public void unlinkToDeath() {
        try {
            mVibration.callerToken.unlinkToDeath(this, 0);
        } catch (NoSuchElementException e) {
            Slog.wtf(TAG, "Failed to unlink vibration to token death", e);
        }
    }

    /**
     * Notify the execution that cancellation is requested. This will be acted upon
     * asynchronously in the VibrationThread.
@@ -452,6 +476,23 @@ final class VibrationStepConductor implements IBinder.DeathRecipient {
        }
    }

    /**
     * Notify that the VibrationThread has completed the vibration effect playback.
     *
     * <p>This is a lightweight method intended to be called by the vibration thread directly. The
     * VibrationThread may still be continuing with cleanup tasks, and should not be given new work
     * until it notifies the manager that it has been released.
     */
    public void notifyVibrationComplete(@NonNull Vibration.EndInfo endInfo) {
        if (Build.IS_DEBUGGABLE) {
            expectIsVibrationThread(true);
        }
        if (DEBUG) {
            Slog.d(TAG, "Vibration " + mVibration.id + " finished with " + endInfo);
        }
        mVibration.end(endInfo);
    }

    /** Returns true if a cancellation signal was sent via {@link #notifyCancelled}. */
    public boolean wasNotifiedToCancel() {
        if (Build.IS_DEBUGGABLE) {
Loading