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

Commit 936a4d9d authored by Lais Andrade's avatar Lais Andrade
Browse files

Changes to VibrationThread in preparation for sessions

- Make session end method async, to follow the vibration thread
  cancelation structure.
- Remove service callback for vibration complete, make thread notify the
  conductor directly.
- Simplify vibration reporting to be triggered only when the thread
  reports the vibration cleanup is complete, remove boolean param.
- Move IBinder link/unlink to death from the thread to the service, as
  sessions will be linked there as well.

Bug: 345414356
Flag: EXEMPT refactor
Test: FrameworksVibratorServicesTests
Change-Id: I2358ec00cbee8569e9a0bce2f0b284d41a3405ae
parent fa55e4a9
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