diff options
| author | 2016-03-16 16:48:31 +0000 | |
|---|---|---|
| committer | 2016-03-16 16:48:33 +0000 | |
| commit | af56824e35341f46418c39e47b6855223a446c63 (patch) | |
| tree | 5929ddb2e4e6d218fec0bbbb7ab37beb704ffe59 | |
| parent | e7f923f52a393fcc1ec61e61df23b23b517fd6e0 (diff) | |
| parent | 48034f89b75ecfa4871855afd7b4f701ff927d28 (diff) | |
Merge "Prevent apps without DND access from toggling DND via AudioService." into nyc-dev
4 files changed, 88 insertions, 18 deletions
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 10aa7ebc136a..0d4729d8349f 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -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(); diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 69d44872d86e..d179171a320e 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -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. diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index d919737c28e2..e7580f4b0879 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -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; diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index eaa0f95f7f7e..3baf894a67f0 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -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); } |