Merge "Add early exits to visitGrantableUri/calculateGrantableUris." into udc-qpr-dev

This commit is contained in:
Ioana Alexandru
2023-08-17 10:24:02 +00:00
committed by Android (Google) Code Review
2 changed files with 46 additions and 45 deletions

View File

@@ -25,8 +25,6 @@ import static android.service.notification.NotificationListenerService.Ranking.U
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_POSITIVE;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -48,6 +46,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.Trace;
import android.os.UserHandle;
import android.os.VibrationEffect;
import android.provider.Settings;
@@ -98,8 +97,7 @@ public final class NotificationRecord {
// the period after which a notification is updated where it can make sound
private static final int MAX_SOUND_DELAY_MS = 2000;
private final StatusBarNotification sbn;
IActivityManager mAm;
UriGrantsManagerInternal mUgmInternal;
private final UriGrantsManagerInternal mUgmInternal;
final int mTargetSdkVersion;
final int mOriginalFlags;
private final Context mContext;
@@ -223,7 +221,6 @@ public final class NotificationRecord {
this.sbn = sbn;
mTargetSdkVersion = LocalServices.getService(PackageManagerInternal.class)
.getPackageTargetSdkVersion(sbn.getPackageName());
mAm = ActivityManager.getService();
mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
mOriginalFlags = sbn.getNotification().flags;
mRankingTimeMs = calculateRankingTimeMs(0L);
@@ -1387,18 +1384,27 @@ public final class NotificationRecord {
* Collect all {@link Uri} that should have permission granted to whoever
* will be rendering it.
*/
protected void calculateGrantableUris() {
final Notification notification = getNotification();
notification.visitUris((uri) -> {
visitGrantableUri(uri, false, false);
});
private void calculateGrantableUris() {
Trace.beginSection("NotificationRecord.calculateGrantableUris");
try {
// We can't grant URI permissions from system.
final int sourceUid = getSbn().getUid();
if (sourceUid == android.os.Process.SYSTEM_UID) return;
if (notification.getChannelId() != null) {
NotificationChannel channel = getChannel();
if (channel != null) {
visitGrantableUri(channel.getSound(), (channel.getUserLockedFields()
& NotificationChannel.USER_LOCKED_SOUND) != 0, true);
final Notification notification = getNotification();
notification.visitUris((uri) -> {
visitGrantableUri(uri, false, false);
});
if (notification.getChannelId() != null) {
NotificationChannel channel = getChannel();
if (channel != null) {
visitGrantableUri(channel.getSound(), (channel.getUserLockedFields()
& NotificationChannel.USER_LOCKED_SOUND) != 0, true);
}
}
} finally {
Trace.endSection();
}
}
@@ -1413,13 +1419,14 @@ public final class NotificationRecord {
private void visitGrantableUri(Uri uri, boolean userOverriddenUri, boolean isSound) {
if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
// We can't grant Uri permissions from system
final int sourceUid = getSbn().getUid();
if (sourceUid == android.os.Process.SYSTEM_UID) return;
if (mGrantableUris != null && mGrantableUris.contains(uri)) {
return; // already verified this URI
}
final int sourceUid = getSbn().getUid();
final long ident = Binder.clearCallingIdentity();
try {
// This will throw SecurityException if caller can't grant
// This will throw a SecurityException if the caller can't grant.
mUgmInternal.checkGrantUriPermission(sourceUid, null,
ContentProvider.getUriWithoutUserId(uri),
Intent.FLAG_GRANT_READ_URI_PERMISSION,

View File

@@ -36,7 +36,7 @@ import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.fail;
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -44,7 +44,6 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.app.Notification;
import android.app.Notification.Builder;
import android.app.NotificationChannel;
@@ -76,6 +75,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.R;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.LocalServices;
import com.android.server.UiServiceTestCase;
import com.android.server.uri.UriGrantsManagerInternal;
@@ -850,84 +850,78 @@ public class NotificationRecordTest extends UiServiceTestCase {
@Test
public void testCalculateGrantableUris_PappProvided() {
IActivityManager am = mock(IActivityManager.class);
UriGrantsManagerInternal ugm = mock(UriGrantsManagerInternal.class);
when(ugm.checkGrantUriPermission(anyInt(), eq(null), any(Uri.class),
anyInt(), anyInt())).thenThrow(new SecurityException());
LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
LocalServices.addService(UriGrantsManagerInternal.class, ugm);
channel.setSound(null, null);
Notification n = new Notification.Builder(mContext, channel.getId())
.setSmallIcon(Icon.createWithContentUri(Uri.parse("content://something")))
.build();
StatusBarNotification sbn =
new StatusBarNotification(PKG_P, PKG_P, id1, tag1, uid, uid, n, mUser, null, uid);
NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
record.mAm = am;
record.mUgmInternal = ugm;
try {
record.calculateGrantableUris();
fail("App provided uri for p targeting app should throw exception");
} catch (SecurityException e) {
// expected
}
assertThrows("App provided uri for p targeting app should throw exception",
SecurityException.class,
() -> new NotificationRecord(mMockContext, sbn, channel));
}
@Test
public void testCalculateGrantableUris_PappProvided_invalidSound() {
IActivityManager am = mock(IActivityManager.class);
UriGrantsManagerInternal ugm = mock(UriGrantsManagerInternal.class);
when(ugm.checkGrantUriPermission(anyInt(), eq(null), any(Uri.class),
anyInt(), anyInt())).thenThrow(new SecurityException());
LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
LocalServices.addService(UriGrantsManagerInternal.class, ugm);
channel.setSound(Uri.parse("content://something"), mock(AudioAttributes.class));
Notification n = mock(Notification.class);
when(n.getChannelId()).thenReturn(channel.getId());
StatusBarNotification sbn =
new StatusBarNotification(PKG_P, PKG_P, id1, tag1, uid, uid, n, mUser, null, uid);
NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
record.mAm = am;
record.mUgmInternal = ugm;
record.calculateGrantableUris();
NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, record.getSound());
}
@Test
public void testCalculateGrantableUris_PuserOverridden() {
IActivityManager am = mock(IActivityManager.class);
UriGrantsManagerInternal ugm = mock(UriGrantsManagerInternal.class);
when(ugm.checkGrantUriPermission(anyInt(), eq(null), any(Uri.class),
anyInt(), anyInt())).thenThrow(new SecurityException());
LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
LocalServices.addService(UriGrantsManagerInternal.class, ugm);
channel.lockFields(NotificationChannel.USER_LOCKED_SOUND);
Notification n = mock(Notification.class);
when(n.getChannelId()).thenReturn(channel.getId());
StatusBarNotification sbn =
new StatusBarNotification(PKG_P, PKG_P, id1, tag1, uid, uid, n, mUser, null, uid);
NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
record.mAm = am;
record.calculateGrantableUris();
new NotificationRecord(mMockContext, sbn, channel); // should not throw
}
@Test
public void testCalculateGrantableUris_prePappProvided() {
IActivityManager am = mock(IActivityManager.class);
UriGrantsManagerInternal ugm = mock(UriGrantsManagerInternal.class);
when(ugm.checkGrantUriPermission(anyInt(), eq(null), any(Uri.class),
anyInt(), anyInt())).thenThrow(new SecurityException());
LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
LocalServices.addService(UriGrantsManagerInternal.class, ugm);
Notification n = mock(Notification.class);
when(n.getChannelId()).thenReturn(channel.getId());
StatusBarNotification sbn =
new StatusBarNotification(PKG_O, PKG_O, id1, tag1, uid, uid, n, mUser, null, uid);
NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
record.mAm = am;
record.calculateGrantableUris();
// should not throw
new NotificationRecord(mMockContext, sbn, channel); // should not throw
}
@Test