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

Commit 3a0f7155 authored by Michael Wright's avatar Michael Wright Committed by android-build-merger
Browse files

Merge "Ignore DND when FLAG_BYPASS_INTERRUPTION_POLICY is set." into qt-r1-dev

am: 3af0a7b5

Change-Id: I4942abf90c783c67f0a32dbbc018a6a3e4d1c76e
parents 5b432e94 3af0a7b5
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.os;

import android.media.AudioAttributes;
import android.os.VibrationEffect;

/** {@hide} */
@@ -23,8 +24,8 @@ interface IVibratorService
{
    boolean hasVibrator();
    boolean hasAmplitudeControl();
    void vibrate(int uid, String opPkg, in VibrationEffect effect, int usageHint, String reason,
            IBinder token);
    void vibrate(int uid, String opPkg, in VibrationEffect effect, in AudioAttributes attributes,
            String reason, IBinder token);
    void cancelVibrate(IBinder token);
}
+1 −5
Original line number Diff line number Diff line
@@ -77,16 +77,12 @@ public class SystemVibrator extends Vibrator {
            return;
        }
        try {
            mService.vibrate(uid, opPkg, effect, usageForAttributes(attributes), reason, mToken);
            mService.vibrate(uid, opPkg, effect, attributes, reason, mToken);
        } catch (RemoteException e) {
            Log.w(TAG, "Failed to vibrate.", e);
        }
    }

    private static int usageForAttributes(AudioAttributes attributes) {
        return attributes != null ? attributes.getUsage() : AudioAttributes.USAGE_UNKNOWN;
    }

    @Override
    public void cancel() {
        if (mService == null) {
+87 −42
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server;

import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.IUidObserver;
@@ -193,7 +194,7 @@ public class VibratorService extends IVibratorService.Stub
        // with other system events, any duration calculations should be done use startTime so as
        // not to be affected by discontinuities created by RTC adjustments.
        public final long startTimeDebug;
        public final int usageHint;
        public final AudioAttributes attrs;
        public final int uid;
        public final String opPkg;
        public final String reason;
@@ -206,12 +207,12 @@ public class VibratorService extends IVibratorService.Stub
        public VibrationEffect originalEffect;

        private Vibration(IBinder token, VibrationEffect effect,
                int usageHint, int uid, String opPkg, String reason) {
                AudioAttributes attrs, int uid, String opPkg, String reason) {
            this.token = token;
            this.effect = effect;
            this.startTime = SystemClock.elapsedRealtime();
            this.startTimeDebug = System.currentTimeMillis();
            this.usageHint = usageHint;
            this.attrs = attrs;
            this.uid = uid;
            this.opPkg = opPkg;
            this.reason = reason;
@@ -231,7 +232,7 @@ public class VibratorService extends IVibratorService.Stub
        }

        public boolean isHapticFeedback() {
            if (VibratorService.this.isHapticFeedback(usageHint)) {
            if (VibratorService.this.isHapticFeedback(attrs.getUsage())) {
                return true;
            }
            if (effect instanceof VibrationEffect.Prebaked) {
@@ -256,15 +257,15 @@ public class VibratorService extends IVibratorService.Stub
        }

        public boolean isNotification() {
            return VibratorService.this.isNotification(usageHint);
            return VibratorService.this.isNotification(attrs.getUsage());
        }

        public boolean isRingtone() {
            return VibratorService.this.isRingtone(usageHint);
            return VibratorService.this.isRingtone(attrs.getUsage());
        }

        public boolean isAlarm() {
            return VibratorService.this.isAlarm(usageHint);
            return VibratorService.this.isAlarm(attrs.getUsage());
        }

        public boolean isFromSystem() {
@@ -273,7 +274,7 @@ public class VibratorService extends IVibratorService.Stub

        public VibrationInfo toInfo() {
            return new VibrationInfo(
                    startTimeDebug, effect, originalEffect, usageHint, uid, opPkg, reason);
                    startTimeDebug, effect, originalEffect, attrs, uid, opPkg, reason);
        }
    }

@@ -281,18 +282,18 @@ public class VibratorService extends IVibratorService.Stub
        private final long mStartTimeDebug;
        private final VibrationEffect mEffect;
        private final VibrationEffect mOriginalEffect;
        private final int mUsageHint;
        private final AudioAttributes mAttrs;
        private final int mUid;
        private final String mOpPkg;
        private final String mReason;

        public VibrationInfo(long startTimeDebug, VibrationEffect effect,
                VibrationEffect originalEffect, int usageHint, int uid,
                VibrationEffect originalEffect, AudioAttributes attrs, int uid,
                String opPkg, String reason) {
            mStartTimeDebug = startTimeDebug;
            mEffect = effect;
            mOriginalEffect = originalEffect;
            mUsageHint = usageHint;
            mAttrs = attrs;
            mUid = uid;
            mOpPkg = opPkg;
            mReason = reason;
@@ -307,8 +308,8 @@ public class VibratorService extends IVibratorService.Stub
                    .append(mEffect)
                    .append(", originalEffect: ")
                    .append(mOriginalEffect)
                    .append(", usageHint: ")
                    .append(mUsageHint)
                    .append(", attrs: ")
                    .append(mAttrs)
                    .append(", uid: ")
                    .append(mUid)
                    .append(", opPkg: ")
@@ -549,12 +550,11 @@ public class VibratorService extends IVibratorService.Stub
    }

    @Override // Binder call
    public void vibrate(int uid, String opPkg, VibrationEffect effect, int usageHint, String reason,
            IBinder token) {
    public void vibrate(int uid, String opPkg, VibrationEffect effect,
            @Nullable AudioAttributes attrs, String reason, IBinder token) {
        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate, reason = " + reason);
        try {
            if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
                    != PackageManager.PERMISSION_GRANTED) {
            if (!hasPermission(android.Manifest.permission.VIBRATE)) {
                throw new SecurityException("Requires VIBRATE permission");
            }
            if (token == null) {
@@ -566,6 +566,22 @@ public class VibratorService extends IVibratorService.Stub
                return;
            }

            if (attrs == null) {
                attrs = new AudioAttributes.Builder()
                        .setUsage(AudioAttributes.USAGE_UNKNOWN)
                        .build();
            }

            if (shouldBypassDnd(attrs)) {
                if (!(hasPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
                        || hasPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
                        || hasPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING))) {
                    final int flags = attrs.getAllFlags()
                            & ~AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY;
                    attrs = new AudioAttributes.Builder(attrs).replaceFlags(flags).build();
                }
            }

            // If our current vibration is longer than the new vibration and is the same amplitude,
            // then just let the current one finish.
            synchronized (mLock) {
@@ -608,13 +624,13 @@ public class VibratorService extends IVibratorService.Stub
                    return;
                }

                Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg, reason);
                Vibration vib = new Vibration(token, effect, attrs, uid, opPkg, reason);
                if (mProcStatesCache.get(uid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)
                        > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
                        && !vib.isNotification() && !vib.isRingtone() && !vib.isAlarm()) {
                    Slog.e(TAG, "Ignoring incoming vibration as process with"
                            + " uid= " + uid + " is background,"
                            + " usage = " + AudioAttributes.usageToString(vib.usageHint));
                            + " attrs= " + vib.attrs);
                    return;
                }
                linkVibration(vib);
@@ -632,6 +648,11 @@ public class VibratorService extends IVibratorService.Stub
        }
    }

    private boolean hasPermission(String permission) {
        return mContext.checkCallingOrSelfPermission(permission)
                == PackageManager.PERMISSION_GRANTED;
    }

    private static boolean isRepeatingVibration(VibrationEffect effect) {
        return effect.getDuration() == Long.MAX_VALUE;
    }
@@ -760,14 +781,14 @@ public class VibratorService extends IVibratorService.Stub
            if (vib.effect instanceof VibrationEffect.OneShot) {
                Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
                VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
                doVibratorOn(oneShot.getDuration(), oneShot.getAmplitude(), vib.uid, vib.usageHint);
                doVibratorOn(oneShot.getDuration(), oneShot.getAmplitude(), vib.uid, vib.attrs);
                mH.postDelayed(mVibrationEndRunnable, oneShot.getDuration());
            } else if (vib.effect instanceof VibrationEffect.Waveform) {
                // mThread better be null here. doCancelVibrate should always be
                // called before startNextVibrationLocked or startVibrationLocked.
                Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
                VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
                mThread = new VibrateThread(waveform, vib.uid, vib.usageHint);
                mThread = new VibrateThread(waveform, vib.uid, vib.attrs);
                mThread.start();
            } else if (vib.effect instanceof VibrationEffect.Prebaked) {
                Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
@@ -788,13 +809,14 @@ public class VibratorService extends IVibratorService.Stub
            return true;
        }

        if (vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
        if (vib.attrs.getUsage() == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
            return true;
        }

        if (vib.usageHint == AudioAttributes.USAGE_ALARM ||
                vib.usageHint == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY ||
                vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) {
        if (vib.attrs.getUsage() == AudioAttributes.USAGE_ALARM
                || vib.attrs.getUsage() == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY
                || vib.attrs.getUsage()
                    == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) {
            return true;
        }

@@ -887,12 +909,24 @@ public class VibratorService extends IVibratorService.Stub
        }
    }

    private static boolean shouldBypassDnd(AudioAttributes attrs) {
        return (attrs.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0;
    }

    private int getAppOpMode(Vibration vib) {
        int mode = mAppOps.checkAudioOpNoThrow(AppOpsManager.OP_VIBRATE,
                vib.usageHint, vib.uid, vib.opPkg);
                vib.attrs.getUsage(), vib.uid, vib.opPkg);
        if (mode == AppOpsManager.MODE_ALLOWED) {
            mode = mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, vib.uid, vib.opPkg);
        }

        if (mode == AppOpsManager.MODE_IGNORED && shouldBypassDnd(vib.attrs)) {
            // If we're just ignoring the vibration op then this is set by DND and we should ignore
            // if we're asked to bypass. AppOps won't be able to record this operation, so make
            // sure we at least note it in the logs for debugging.
            Slog.d(TAG, "Bypassing DND for vibration: " + vib);
            mode = AppOpsManager.MODE_ALLOWED;
        }
        return mode;
    }

@@ -1032,7 +1066,7 @@ public class VibratorService extends IVibratorService.Stub
        return vibratorExists();
    }

    private void doVibratorOn(long millis, int amplitude, int uid, int usageHint) {
    private void doVibratorOn(long millis, int amplitude, int uid, AudioAttributes attrs) {
        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn");
        try {
            synchronized (mInputDeviceVibrators) {
@@ -1046,10 +1080,8 @@ public class VibratorService extends IVibratorService.Stub
                noteVibratorOnLocked(uid, millis);
                final int vibratorCount = mInputDeviceVibrators.size();
                if (vibratorCount != 0) {
                    final AudioAttributes attributes =
                            new AudioAttributes.Builder().setUsage(usageHint).build();
                    for (int i = 0; i < vibratorCount; i++) {
                        mInputDeviceVibrators.get(i).vibrate(millis, attributes);
                        mInputDeviceVibrators.get(i).vibrate(millis, attrs);
                    }
                } else {
                    // Note: ordering is important here! Many haptic drivers will reset their
@@ -1118,7 +1150,7 @@ public class VibratorService extends IVibratorService.Stub
                Slog.w(TAG, "Failed to play prebaked effect, no fallback");
                return 0;
            }
            Vibration fallbackVib = new Vibration(vib.token, effect, vib.usageHint, vib.uid,
            Vibration fallbackVib = new Vibration(vib.token, effect, vib.attrs, vib.uid,
                    vib.opPkg, vib.reason + " (fallback)");
            final int intensity = getCurrentIntensityLocked(fallbackVib);
            linkVibration(fallbackVib);
@@ -1213,14 +1245,14 @@ public class VibratorService extends IVibratorService.Stub
    private class VibrateThread extends Thread {
        private final VibrationEffect.Waveform mWaveform;
        private final int mUid;
        private final int mUsageHint;
        private final AudioAttributes mAttrs;

        private boolean mForceStop;

        VibrateThread(VibrationEffect.Waveform waveform, int uid, int usageHint) {
        VibrateThread(VibrationEffect.Waveform waveform, int uid, AudioAttributes attrs) {
            mWaveform = waveform;
            mUid = uid;
            mUsageHint = usageHint;
            mAttrs = attrs;
            mTmpWorkSource.set(uid);
            mWakeLock.setWorkSource(mTmpWorkSource);
        }
@@ -1295,7 +1327,7 @@ public class VibratorService extends IVibratorService.Stub
                                    // appropriate intervals.
                                    onDuration = getTotalOnDuration(timings, amplitudes, index - 1,
                                            repeat);
                                    doVibratorOn(onDuration, amplitude, mUid, mUsageHint);
                                    doVibratorOn(onDuration, amplitude, mUid, mAttrs);
                                } else {
                                    doVibratorSetAmplitude(amplitude);
                                }
@@ -1612,8 +1644,9 @@ public class VibratorService extends IVibratorService.Stub

                VibrationEffect effect =
                        VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE);
                vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
                        "Shell Command", mToken);
                AudioAttributes attrs = createAudioAttributes(commonOptions);
                vibrate(Binder.getCallingUid(), description, effect, attrs, "Shell Command",
                        mToken);
                return 0;
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
@@ -1672,8 +1705,9 @@ public class VibratorService extends IVibratorService.Stub
                            amplitudesList.stream().mapToInt(Integer::intValue).toArray();
                    effect = VibrationEffect.createWaveform(timings, amplitudes, repeat);
                }
                vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
                        "Shell Command", mToken);
                AudioAttributes attrs = createAudioAttributes(commonOptions);
                vibrate(Binder.getCallingUid(), description, effect, attrs, "Shell Command",
                        mToken);
                return 0;
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
@@ -1703,14 +1737,25 @@ public class VibratorService extends IVibratorService.Stub

                VibrationEffect effect =
                        VibrationEffect.get(id, false);
                vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
                        "Shell Command", mToken);
                AudioAttributes attrs = createAudioAttributes(commonOptions);
                vibrate(Binder.getCallingUid(), description, effect, attrs, "Shell Command",
                        mToken);
                return 0;
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
            }
        }

        private AudioAttributes createAudioAttributes(CommonOptions commonOptions) {
            final int flags = commonOptions.force
                    ? AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY
                    : 0;
            return new AudioAttributes.Builder()
                    .setUsage(AudioAttributes.USAGE_UNKNOWN)
                    .setFlags(flags)
                    .build();
        }

        @Override
        public void onHelp() {
            try (PrintWriter pw = getOutPrintWriter();) {
+8 −4
Original line number Diff line number Diff line
@@ -16,9 +16,7 @@

package com.android.framework.permission.tests;

import junit.framework.TestCase;

import android.media.AudioManager;
import android.media.AudioAttributes;
import android.os.Binder;
import android.os.IVibratorService;
import android.os.Process;
@@ -27,6 +25,9 @@ import android.os.ServiceManager;
import android.os.VibrationEffect;
import android.test.suitebuilder.annotation.SmallTest;

import junit.framework.TestCase;


/**
 * Verify that Hardware apis cannot be called without required permissions.
 */
@@ -51,7 +52,10 @@ public class VibratorServicePermissionTest extends TestCase {
        try {
            final VibrationEffect effect =
                    VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE);
            mVibratorService.vibrate(Process.myUid(), null, effect, AudioManager.STREAM_ALARM,
            final AudioAttributes attrs = new AudioAttributes.Builder()
                    .setUsage(AudioAttributes.USAGE_ALARM)
                    .build();
            mVibratorService.vibrate(Process.myUid(), null, effect, attrs,
                    "testVibrate", new Binder());
            fail("vibrate did not throw SecurityException as expected");
        } catch (SecurityException e) {