Merge "Prevent apps without DND access from toggling DND via AudioService." into nyc-dev

This commit is contained in:
Julia Reynolds
2016-03-16 16:48:31 +00:00
committed by Android (Google) Code Review
4 changed files with 88 additions and 18 deletions

View File

@@ -913,10 +913,6 @@ public class NotificationManager
* (e.g. via sound & vibration) and is applied globally.
* @return One of the INTERRUPTION_FILTER_ constants, or INTERRUPTION_FILTER_UNKNOWN when
* unavailable.
*
* <p>
* Only available if policy access is granted to this package.
* See {@link #isNotificationPolicyAccessGranted}.
*/
public final @InterruptionFilter int getCurrentInterruptionFilter() {
final INotificationManager service = getService();

View File

@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothDevice;
import android.content.ComponentName;
@@ -1004,6 +1005,9 @@ public class AudioManager {
* according to user settings.
* <p>This method has no effect if the device implements a fixed volume policy
* as indicated by {@link #isVolumeFixed()}.
* * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
* unless the app has been granted Do Not Disturb Access.
* See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
* @param ringerMode The ringer mode, one of {@link #RINGER_MODE_NORMAL},
* {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
* @see #getRingerMode()
@@ -1025,6 +1029,9 @@ public class AudioManager {
* Sets the volume index for a particular stream.
* <p>This method has no effect if the device implements a fixed volume policy
* as indicated by {@link #isVolumeFixed()}.
* <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
* the app has been granted Do Not Disturb Access.
* See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
* @param streamType The stream whose volume index should be set.
* @param index The volume index to set. See
* {@link #getStreamMaxVolume(int)} for the largest valid value.
@@ -1069,6 +1076,9 @@ public class AudioManager {
* <p>
* This method has no effect if the device implements a fixed volume policy
* as indicated by {@link #isVolumeFixed()}.
* <p>From N onward, stream mute changes that would toggle Do Not Disturb are not allowed unless
* the app has been granted Do Not Disturb Access.
* See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
* <p>
* This method was deprecated in API level 22. Prior to API level 22 this
* method had significantly different behavior and should be used carefully.

View File

@@ -28,6 +28,7 @@ import android.app.ActivityManagerInternal;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.NotificationManager;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
@@ -40,6 +41,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
@@ -105,9 +107,6 @@ import android.util.MathUtils;
import android.util.Slog;
import android.util.SparseIntArray;
import android.view.KeyEvent;
import android.view.OrientationEventListener;
import android.view.Surface;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
import com.android.internal.util.XmlUtils;
@@ -557,6 +556,7 @@ public class AudioService extends IAudioService.Stub {
private static Long mLastDeviceConnectMsgTime = new Long(0);
private NotificationManager mNm;
private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
private VolumePolicy mVolumePolicy = VolumePolicy.DEFAULT;
private long mLoweredFromNormalToVibrateTime;
@@ -751,6 +751,8 @@ public class AudioService extends IAudioService.Stub {
}
}
mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
sendMsg(mAudioHandler,
MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
SENDMSG_REPLACE,
@@ -1293,7 +1295,7 @@ public class AudioService extends IAudioService.Stub {
// Check if the ringer mode handles this adjustment. If it does we don't
// need to adjust the volume further.
final int result = checkForRingerModeChange(aliasIndex, direction, step,
streamState.mIsMuted);
streamState.mIsMuted, caller);
adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
// If suppressing a volume adjustment in silent mode, display the UI hint
if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
@@ -1309,7 +1311,6 @@ public class AudioService extends IAudioService.Stub {
&& (mRingerModeMutedStreams & (1 << AudioSystem.STREAM_MUSIC)) != 0) {
adjustVolume = false;
}
int oldIndex = mStreamStates[streamType].getIndex(device);
if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
@@ -1453,10 +1454,7 @@ public class AudioService extends IAudioService.Stub {
}
};
private void onSetStreamVolume(int streamType, int index, int flags, int device,
String caller) {
final int stream = mStreamVolumeAlias[streamType];
setStreamVolumeInt(stream, index, device, false, caller);
private int getNewRingerMode(int stream, int index, int flags) {
// setting volume on ui sounds stream type also controls silent mode
if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
(stream == getUiSoundsStreamType())) {
@@ -1464,11 +1462,49 @@ public class AudioService extends IAudioService.Stub {
if (index == 0) {
newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
: mVolumePolicy.volumeDownToEnterSilent ? AudioManager.RINGER_MODE_SILENT
: AudioManager.RINGER_MODE_NORMAL;
: AudioManager.RINGER_MODE_NORMAL;
} else {
newRingerMode = AudioManager.RINGER_MODE_NORMAL;
}
setRingerMode(newRingerMode, TAG + ".onSetStreamVolume", false /*external*/);
return newRingerMode;
}
return getRingerModeExternal();
}
private boolean isAndroidNPlus(String caller) {
try {
final ApplicationInfo applicationInfo =
mContext.getPackageManager().getApplicationInfoAsUser(
caller, 0, UserHandle.getUserId(Binder.getCallingUid()));
if (applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
return true;
}
return false;
} catch (PackageManager.NameNotFoundException e) {
return true;
}
}
private boolean wouldToggleZenMode(int newMode) {
if (getRingerModeExternal() == AudioManager.RINGER_MODE_SILENT
&& newMode != AudioManager.RINGER_MODE_SILENT) {
return true;
} else if (getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT
&& newMode == AudioManager.RINGER_MODE_SILENT) {
return true;
}
return false;
}
private void onSetStreamVolume(int streamType, int index, int flags, int device,
String caller) {
final int stream = mStreamVolumeAlias[streamType];
setStreamVolumeInt(stream, index, device, false, caller);
// setting volume on ui sounds stream type also controls silent mode
if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
(stream == getUiSoundsStreamType())) {
setRingerMode(getNewRingerMode(stream, index, flags),
TAG + ".onSetStreamVolume", false /*external*/);
}
// setting non-zero volume for a muted stream unmutes the stream and vice versa
mStreamStates[stream].mute(index == 0);
@@ -1509,6 +1545,12 @@ public class AudioService extends IAudioService.Stub {
return;
}
if (isAndroidNPlus(callingPackage)
&& wouldToggleZenMode(getNewRingerMode(streamTypeAlias, index, flags))
&& !mNm.isNotificationPolicyAccessGrantedForPackage(callingPackage)) {
throw new SecurityException("Not allowed to change Do Not Disturb state");
}
synchronized (mSafeMediaVolumeState) {
// reset any pending volume command
mPendingVolumeCommand = null;
@@ -2005,6 +2047,11 @@ public class AudioService extends IAudioService.Stub {
}
public void setRingerModeExternal(int ringerMode, String caller) {
if (isAndroidNPlus(caller) && wouldToggleZenMode(ringerMode)
&& !mNm.isNotificationPolicyAccessGrantedForPackage(caller)) {
throw new SecurityException("Not allowed to change Do Not Disturb state");
}
setRingerMode(ringerMode, caller, true /*external*/);
}
@@ -3328,7 +3375,8 @@ public class AudioService extends IAudioService.Stub {
* adjusting volume. If so, this will set the proper ringer mode and volume
* indices on the stream states.
*/
private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted) {
private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted,
String caller) {
final boolean isTv = mPlatformType == AudioSystem.PLATFORM_TELEVISION;
int result = FLAG_ADJUST_VOLUME;
int ringerMode = getRingerModeInternal();
@@ -3417,6 +3465,11 @@ public class AudioService extends IAudioService.Stub {
break;
}
if (isAndroidNPlus(caller) && wouldToggleZenMode(ringerMode)
&& !mNm.isNotificationPolicyAccessGrantedForPackage(caller)) {
throw new SecurityException("Not allowed to change Do Not Disturb state");
}
setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
mPrevVolDirection = direction;

View File

@@ -1807,6 +1807,16 @@ public class NotificationManagerService extends SystemService {
message);
}
private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
try {
checkCallerIsSystemOrSameApp(pkg);
} catch (SecurityException e) {
getContext().enforceCallingPermission(
android.Manifest.permission.STATUS_BAR_SERVICE,
message);
}
}
private void enforcePolicyAccess(int uid, String method) {
if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
@@ -1933,8 +1943,9 @@ public class NotificationManagerService extends SystemService {
}
@Override
public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {
enforceSystemOrSystemUI("request policy access status for another package");
public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
enforceSystemOrSystemUIOrSamePackage(pkg,
"request policy access status for another package");
return checkPackagePolicyAccess(pkg);
}