summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Wright <michaelwr@google.com>2019-06-25 13:50:46 -0700
committerandroid-build-merger <android-build-merger@google.com>2019-06-25 13:50:46 -0700
commit3a0f71558844198a72a931be991950ebe12ddb36 (patch)
tree1ac40635148bd99eee07dd838ad663057e2a36d0
parent5b432e94f00dddfd54c1f3bd8abb246cfbb80a3e (diff)
parent3af0a7b5e5b4d412ea9b793dbdf7d8770c2b5bdc (diff)
Merge "Ignore DND when FLAG_BYPASS_INTERRUPTION_POLICY is set." into qt-r1-dev
am: 3af0a7b5e5 Change-Id: I4942abf90c783c67f0a32dbbc018a6a3e4d1c76e
-rw-r--r--core/java/android/os/IVibratorService.aidl5
-rw-r--r--core/java/android/os/SystemVibrator.java6
-rw-r--r--services/core/java/com/android/server/VibratorService.java129
-rw-r--r--tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java12
4 files changed, 99 insertions, 53 deletions
diff --git a/core/java/android/os/IVibratorService.aidl b/core/java/android/os/IVibratorService.aidl
index e8b3ca6cb7ae..1456ff7e6c5e 100644
--- a/core/java/android/os/IVibratorService.aidl
+++ b/core/java/android/os/IVibratorService.aidl
@@ -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);
}
diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java
index 4af514abfd69..a5188e7cd58d 100644
--- a/core/java/android/os/SystemVibrator.java
+++ b/core/java/android/os/SystemVibrator.java
@@ -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) {
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 6eb9f0c7a6bc..07482796b027 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -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));
+ + " uid= " + uid + " is background,"
+ + " 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();) {
diff --git a/tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java b/tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java
index 388c7d03dff2..c50229ae30f4 100644
--- a/tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java
+++ b/tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java
@@ -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) {