Add implicit grants to NLSes

So they can query packages they are receiving notifications
from without needing to hold QUERY_ALL_PACKAGES.

Test: NotificationListenersTest, manual with test app
Fixes: 184736797
Change-Id: I8071d5a03515cc05cbd3f8598997e6236d306052
This commit is contained in:
Julia Reynolds
2022-04-15 15:05:44 -04:00
parent 214438ff38
commit 534e6d5fcc
2 changed files with 49 additions and 4 deletions

View File

@@ -494,7 +494,7 @@ public class NotificationManagerService extends SystemService {
private ActivityManagerInternal mAmi;
private IPackageManager mPackageManager;
private PackageManager mPackageManagerClient;
private PackageManagerInternal mPackageManagerInternal;
PackageManagerInternal mPackageManagerInternal;
private PermissionPolicyInternal mPermissionPolicyInternal;
AudioManager mAudioManager;
AudioManagerInternal mAudioManagerInternal;
@@ -9779,7 +9779,7 @@ public class NotificationManagerService extends SystemService {
* notifications visible to the given listener.
*/
@GuardedBy("mNotificationLock")
private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
final int N = mNotificationList.size();
final ArrayList<NotificationListenerService.Ranking> rankings = new ArrayList<>();
@@ -10894,7 +10894,7 @@ public class NotificationManagerService extends SystemService {
TrimCache trimCache = new TrimCache(sbn);
for (final ManagedServiceInfo info : getServices()) {
boolean sbnVisible = isVisibleToListener(sbn, r. getNotificationType(), info);
boolean sbnVisible = isVisibleToListener(sbn, r.getNotificationType(), info);
boolean oldSbnVisible = (oldSbn != null)
&& isVisibleToListener(oldSbn, old.getNotificationType(), info);
// This notification hasn't been and still isn't visible -> ignore.
@@ -10924,12 +10924,17 @@ public class NotificationManagerService extends SystemService {
info, oldSbnLightClone, update, null, REASON_USER_STOPPED));
continue;
}
// Grant access before listener is notified
final int targetUserId = (info.userid == UserHandle.USER_ALL)
? UserHandle.USER_SYSTEM : info.userid;
updateUriPermissions(r, old, info.component.getPackageName(), targetUserId);
mPackageManagerInternal.grantImplicitAccess(
targetUserId, null /* intent */,
UserHandle.getAppId(info.uid),
sbn.getUid(),
false /* direct */, false /* retainOnUpdate */);
final StatusBarNotification sbnToPost = trimCache.ForListener(info);
mHandler.post(() -> notifyPosted(info, sbnToPost, update));
}

View File

@@ -28,6 +28,7 @@ import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.atLeast;
@@ -40,16 +41,23 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.INotificationManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.content.pm.VersionedPackage;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IInterface;
import android.os.UserHandle;
import android.service.notification.NotificationListenerFilter;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationStats;
import android.service.notification.NotificationRankingUpdate;
import android.service.notification.StatusBarNotification;
import android.testing.TestableContext;
import android.util.ArraySet;
@@ -60,6 +68,8 @@ import android.util.Xml;
import com.android.server.UiServiceTestCase;
import com.google.common.collect.ImmutableList;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
@@ -457,4 +467,34 @@ public class NotificationListenersTest extends UiServiceTestCase {
mListeners.notifyRemovedLocked(r, 0, rs);
verify(r, never()).getSbn();
}
@Test
public void testImplicitGrant() {
String pkg = "pkg";
int uid = 9;
NotificationChannel channel = new NotificationChannel("id", "name",
NotificationManager.IMPORTANCE_HIGH);
Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
.setContentTitle("foo")
.setSmallIcon(android.R.drawable.sym_def_app_icon)
.setTimeoutAfter(1);
StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, 8, "tag", uid, 0,
nb.build(), UserHandle.getUserHandleForUid(uid), null, 0);
NotificationRecord r = new NotificationRecord(mContext, sbn, channel);
ManagedServices.ManagedServiceInfo info = mListeners.new ManagedServiceInfo(
null, new ComponentName("a", "a"), sbn.getUserId(), false, null, 33, 33);
List<ManagedServices.ManagedServiceInfo> services = ImmutableList.of(info);
when(mListeners.getServices()).thenReturn(services);
when(mNm.isVisibleToListener(any(), anyInt(), any())).thenReturn(true);
when(mNm.makeRankingUpdateLocked(info)).thenReturn(mock(NotificationRankingUpdate.class));
mNm.mPackageManagerInternal = mPmi;
mListeners.notifyPostedLocked(r, null);
verify(mPmi).grantImplicitAccess(sbn.getUserId(), null, UserHandle.getAppId(33),
sbn.getUid(), false, false);
}
}