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

Commit 764b6134 authored by Iavor-Valentin Iftime's avatar Iavor-Valentin Iftime Committed by Android (Google) Code Review
Browse files

Merge "Check sound Uri permission when creating a notification channel" into main

parents 0f4f38ce 94fc92cf
Loading
Loading
Loading
Loading
+2 −7
Original line number Diff line number Diff line
@@ -2579,6 +2579,7 @@ public class NotificationManagerService extends SystemService {
                mNotificationChannelLogger,
                mAppOps,
                mUserProfiles,
                mUgmInternal,
                mShowReviewPermissionsNotification,
                Clock.systemUTC());
        mRankingHelper = new RankingHelper(getContext(), mRankingHandler, mPreferencesHelper,
@@ -6672,13 +6673,7 @@ public class NotificationManagerService extends SystemService {
            final Uri originalSoundUri =
                    (originalChannel != null) ? originalChannel.getSound() : null;
            if (soundUri != null && !Objects.equals(originalSoundUri, soundUri)) {
                Binder.withCleanCallingIdentity(() -> {
                    mUgmInternal.checkGrantUriPermission(sourceUid, null,
                            ContentProvider.getUriWithoutUserId(soundUri),
                            Intent.FLAG_GRANT_READ_URI_PERMISSION,
                            ContentProvider.getUserIdFromUri(soundUri,
                            UserHandle.getUserId(sourceUid)));
                });
                PermissionHelper.grantUriPermission(mUgmInternal, soundUri, sourceUid);
            }
        }
+52 −4
Original line number Diff line number Diff line
@@ -1493,14 +1493,23 @@ public final class NotificationRecord {

            final Notification notification = getNotification();
            notification.visitUris((uri) -> {
                if (com.android.server.notification.Flags.notificationVerifyChannelSoundUri()) {
                    visitGrantableUri(uri, false, false);
                } else {
                    oldVisitGrantableUri(uri, false, false);
                }
            });

            if (notification.getChannelId() != null) {
                NotificationChannel channel = getChannel();
                if (channel != null) {
                    if (com.android.server.notification.Flags.notificationVerifyChannelSoundUri()) {
                        visitGrantableUri(channel.getSound(), (channel.getUserLockedFields()
                                & NotificationChannel.USER_LOCKED_SOUND) != 0, true);
                    } else {
                        oldVisitGrantableUri(channel.getSound(), (channel.getUserLockedFields()
                                & NotificationChannel.USER_LOCKED_SOUND) != 0, true);
                    }
                }
            }
        } finally {
@@ -1516,7 +1525,7 @@ public final class NotificationRecord {
     * {@link #mGrantableUris}. Otherwise, this will either log or throw
     * {@link SecurityException} depending on target SDK of enqueuing app.
     */
    private void visitGrantableUri(Uri uri, boolean userOverriddenUri, boolean isSound) {
    private void oldVisitGrantableUri(Uri uri, boolean userOverriddenUri, boolean isSound) {
        if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;

        if (mGrantableUris != null && mGrantableUris.contains(uri)) {
@@ -1555,6 +1564,45 @@ public final class NotificationRecord {
        }
    }

    /**
     * Note the presence of a {@link Uri} that should have permission granted to
     * whoever will be rendering it.
     * <p>
     * If the enqueuing app has the ability to grant access, it will be added to
     * {@link #mGrantableUris}. Otherwise, this will either log or throw
     * {@link SecurityException} depending on target SDK of enqueuing app.
     */
    private void visitGrantableUri(Uri uri, boolean userOverriddenUri,
            boolean isSound) {
        if (mGrantableUris != null && mGrantableUris.contains(uri)) {
            return; // already verified this URI
        }

        final int sourceUid = getSbn().getUid();
        try {
            PermissionHelper.grantUriPermission(mUgmInternal, uri, sourceUid);

            if (mGrantableUris == null) {
                mGrantableUris = new ArraySet<>();
            }
            mGrantableUris.add(uri);
        } catch (SecurityException e) {
            if (!userOverriddenUri) {
                if (isSound) {
                    mSound = Settings.System.DEFAULT_NOTIFICATION_URI;
                    Log.w(TAG, "Replacing " + uri + " from " + sourceUid + ": " + e.getMessage());
                } else {
                    if (mTargetSdkVersion >= Build.VERSION_CODES.P) {
                        throw e;
                    } else {
                        Log.w(TAG,
                                "Ignoring " + uri + " from " + sourceUid + ": " + e.getMessage());
                    }
                }
            }
        }
    }

    public LogMaker getLogMaker(long now) {
        LogMaker lm = getSbn().getLogMaker()
                .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE, mImportance)
+20 −1
Original line number Diff line number Diff line
@@ -25,19 +25,25 @@ import android.Manifest;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.companion.virtual.VirtualDeviceManager;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.net.Uri;
import android.os.Binder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.permission.IPermissionManager;
import android.util.ArrayMap;
import android.util.Pair;
import android.util.Slog;

import com.android.internal.util.ArrayUtils;
import com.android.server.uri.UriGrantsManagerInternal;

import java.util.Collections;
import java.util.HashSet;
@@ -298,6 +304,19 @@ public final class PermissionHelper {
        return false;
    }

    static void grantUriPermission(final UriGrantsManagerInternal ugmInternal, Uri uri,
            int sourceUid) {
        if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;

        Binder.withCleanCallingIdentity(() -> {
            // This will throw a SecurityException if the caller can't grant.
            ugmInternal.checkGrantUriPermission(sourceUid, null,
                    ContentProvider.getUriWithoutUserId(uri),
                    Intent.FLAG_GRANT_READ_URI_PERMISSION,
                    ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
        });
    }

    public static class PackagePermission {
        public final String packageName;
        public final @UserIdInt int userId;
+11 −0
Original line number Diff line number Diff line
@@ -94,6 +94,7 @@ import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.notification.PermissionHelper.PackagePermission;
import com.android.server.uri.UriGrantsManagerInternal;

import org.json.JSONArray;
import org.json.JSONException;
@@ -219,6 +220,7 @@ public class PreferencesHelper implements RankingConfig {
    private final NotificationChannelLogger mNotificationChannelLogger;
    private final AppOpsManager mAppOps;
    private final ManagedServices.UserProfiles mUserProfiles;
    private final UriGrantsManagerInternal mUgmInternal;

    private SparseBooleanArray mBadgingEnabled;
    private SparseBooleanArray mBubblesEnabled;
@@ -239,6 +241,7 @@ public class PreferencesHelper implements RankingConfig {
            ZenModeHelper zenHelper, PermissionHelper permHelper, PermissionManager permManager,
            NotificationChannelLogger notificationChannelLogger,
            AppOpsManager appOpsManager, ManagedServices.UserProfiles userProfiles,
            UriGrantsManagerInternal ugmInternal,
            boolean showReviewPermissionsNotification, Clock clock) {
        mContext = context;
        mZenModeHelper = zenHelper;
@@ -249,6 +252,7 @@ public class PreferencesHelper implements RankingConfig {
        mNotificationChannelLogger = notificationChannelLogger;
        mAppOps = appOpsManager;
        mUserProfiles = userProfiles;
        mUgmInternal = ugmInternal;
        mShowReviewPermissionsNotification = showReviewPermissionsNotification;
        mIsMediaNotificationFilteringEnabled = context.getResources()
                .getBoolean(R.bool.config_quickSettingsShowMediaPlayer);
@@ -1169,6 +1173,13 @@ public class PreferencesHelper implements RankingConfig {
                }
                clearLockedFieldsLocked(channel);

                // Verify that the app has permission to read the sound Uri
                // Only check for new channels, as regular apps can only set sound
                // before creating. See: {@link NotificationChannel#setSound}
                if (Flags.notificationVerifyChannelSoundUri()) {
                    PermissionHelper.grantUriPermission(mUgmInternal, channel.getSound(), uid);
                }

                channel.setImportanceLockedByCriticalDeviceFunction(
                        r.defaultAppLockedImportance || r.fixedImportance);

+10 −0
Original line number Diff line number Diff line
@@ -170,3 +170,13 @@ flag {
  description: "This flag enables sound uri with vibration source"
  bug: "358524009"
}

flag {
  name: "notification_verify_channel_sound_uri"
  namespace: "systemui"
  description: "Verify Uri permission for sound when creating a notification channel"
  bug: "337775777"
  metadata {
    purpose: PURPOSE_BUGFIX
  }
}
Loading