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

Commit dbe67576 authored by Julia Reynolds's avatar Julia Reynolds Committed by Android (Google) Code Review
Browse files

Merge "Fix binder error when an app has many channels"

parents 48652504 4ce06695
Loading
Loading
Loading
Loading
+14 −3
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Intent;
import android.content.pm.ParceledListSlice;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -68,7 +69,7 @@ public final class NotificationChannelGroup implements Parcelable {
    private CharSequence mName;
    private String mDescription;
    private boolean mBlocked;
    private List<NotificationChannel> mChannels = new ArrayList<>();
    private List<NotificationChannel> mChannels = new ArrayList();
    // Bitwise representation of fields that have been changed by the user
    private int mUserLockedFields;

@@ -106,7 +107,12 @@ public final class NotificationChannelGroup implements Parcelable {
        } else {
            mDescription = null;
        }
        in.readParcelableList(mChannels, NotificationChannel.class.getClassLoader(), android.app.NotificationChannel.class);
        if (in.readByte() != 0) {
            mChannels = in.readParcelable(NotificationChannelGroup.class.getClassLoader(),
                    ParceledListSlice.class).getList();
        } else {
            mChannels = new ArrayList<>();
        }
        mBlocked = in.readBoolean();
        mUserLockedFields = in.readInt();
    }
@@ -138,7 +144,12 @@ public final class NotificationChannelGroup implements Parcelable {
        } else {
            dest.writeByte((byte) 0);
        }
        dest.writeParcelableList(mChannels, flags);
        if (mChannels != null) {
            dest.writeByte((byte) 1);
            dest.writeParcelable(new ParceledListSlice<>(mChannels), flags);
        } else {
            dest.writeByte((byte) 0);
        }
        dest.writeBoolean(mBlocked);
        dest.writeInt(mUserLockedFields);
    }
+8 −0
Original line number Diff line number Diff line
@@ -1740,6 +1740,14 @@ abstract public class ManagedServices {
            return ManagedServices.this;
        }

        public IInterface getService() {
            return service;
        }

        public boolean isSystem() {
            return isSystem;
        }

        @Override
        public String toString() {
            return new StringBuilder("ManagedServiceInfo[")
+5 −4
Original line number Diff line number Diff line
@@ -9974,8 +9974,9 @@ public class NotificationManagerService extends SystemService {
     * instance per user, we want to filter out interactions that are not for the user that the
     * given NAS is bound in.
     */
    private boolean isInteractionVisibleToListener(ManagedServiceInfo info, int userId) {
        boolean isAssistantService = isServiceTokenValid(info.service);
    @VisibleForTesting
    boolean isInteractionVisibleToListener(ManagedServiceInfo info, int userId) {
        boolean isAssistantService = isServiceTokenValid(info.getService());
        return !isAssistantService || info.isSameUser(userId);
    }
@@ -11273,7 +11274,7 @@ public class NotificationManagerService extends SystemService {
                }
                BackgroundThread.getHandler().post(() -> {
                    if (info.isSystem || hasCompanionDevice(info)) {
                    if (info.isSystem() || hasCompanionDevice(info)) {
                        notifyNotificationChannelGroupChanged(
                                info, pkg, user, group, modificationType);
                    }
@@ -11356,7 +11357,7 @@ public class NotificationManagerService extends SystemService {
        private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
                final String pkg, final UserHandle user, final NotificationChannelGroup group,
                final int modificationType) {
            final INotificationListener listener = (INotificationListener) info.service;
            final INotificationListener listener = (INotificationListener) info.getService();
            try {
                listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
            } catch (RemoteException ex) {
+52 −2
Original line number Diff line number Diff line
@@ -28,24 +28,29 @@ import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;

import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.intThat;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
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.NotificationChannelGroup;
import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.pm.IPackageManager;
@@ -54,7 +59,10 @@ import android.content.pm.ServiceInfo;
import android.content.pm.VersionedPackage;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.UserHandle;
import android.service.notification.INotificationListener;
import android.service.notification.NotificationListenerFilter;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationRankingUpdate;
@@ -63,10 +71,10 @@ import android.service.notification.StatusBarNotification;
import android.testing.TestableContext;
import android.util.ArraySet;
import android.util.Pair;
import android.util.Xml;

import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import android.util.Xml;

import com.android.server.UiServiceTestCase;

import com.google.common.collect.ImmutableList;
@@ -113,6 +121,8 @@ public class NotificationListenersTest extends UiServiceTestCase {
        getContext().setMockPackageManager(mPm);
        doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any());

        when(mNm.isInteractionVisibleToListener(any(), anyInt())).thenReturn(true);

        mListeners = spy(mNm.new NotificationListeners(
                mContext, new Object(), mock(ManagedServices.UserProfiles.class), miPm));
        when(mNm.getBinderService()).thenReturn(mINm);
@@ -596,4 +606,44 @@ public class NotificationListenersTest extends UiServiceTestCase {
        verify(mPmi).grantImplicitAccess(sbn.getUserId(), null, UserHandle.getAppId(33),
                sbn.getUid(), false, false);
    }

    @Test
    public void testUpdateGroup_notifyTwoListeners() throws Exception {
        final NotificationChannelGroup updated = new NotificationChannelGroup("id", "name");
        updated.setChannels(ImmutableList.of(
                new NotificationChannel("a", "a", 1), new NotificationChannel("b", "b", 2)));
        updated.setBlocked(true);

        ManagedServices.ManagedServiceInfo i1 = getParcelingListener(updated);
        ManagedServices.ManagedServiceInfo i2= getParcelingListener(updated);
        when(mListeners.getServices()).thenReturn(ImmutableList.of(i1, i2));
        NotificationChannelGroup existing = new NotificationChannelGroup("id", "name");

        mListeners.notifyNotificationChannelGroupChanged("pkg", UserHandle.of(0), updated, 0);
        Thread.sleep(500);

        verify(((INotificationListener) i1.getService()), times(1))
                .onNotificationChannelGroupModification(anyString(), any(), any(), anyInt());
    }

    private ManagedServices.ManagedServiceInfo getParcelingListener(
            final NotificationChannelGroup toParcel)
            throws RemoteException {
        ManagedServices.ManagedServiceInfo i1 = mock(ManagedServices.ManagedServiceInfo.class);
        when(i1.isSystem()).thenReturn(true);
        INotificationListener l1 = mock(INotificationListener.class);
        when(i1.enabledAndUserMatches(anyInt())).thenReturn(true);
        doAnswer(invocationOnMock -> {
            try {
                toParcel.writeToParcel(Parcel.obtain(), 0);
            } catch (Exception e) {
                fail("Failed to parcel group to listener");
                return e;

            }
            return null;
        }).when(l1).onNotificationChannelGroupModification(anyString(), any(), any(), anyInt());
        when(i1.getService()).thenReturn(l1);
        return i1;
    }
}
+30 −0
Original line number Diff line number Diff line
@@ -93,6 +93,7 @@ import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -2448,6 +2449,35 @@ public class PreferencesHelperTest extends UiServiceTestCase {
                mLogger.get(6).event);  // Final log is the deletion of the channel.
    }

    @Test
    public void testGetNotificationChannelGroup() throws Exception {
        NotificationChannelGroup notDeleted = new NotificationChannelGroup("not", "deleted");
        NotificationChannel base =
                new NotificationChannel("not deleted", "belongs to notDeleted", IMPORTANCE_DEFAULT);
        base.setGroup("not");
        NotificationChannel convo =
                new NotificationChannel("convo", "belongs to notDeleted", IMPORTANCE_DEFAULT);
        convo.setGroup("not");
        convo.setConversationId("not deleted", "banana");

        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, notDeleted, true);
        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, base, true, false);
        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, convo, true, false);
        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, notDeleted, true);

        NotificationChannelGroup g
                = mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG_N_MR1, UID_N_MR1);
        Parcel parcel = Parcel.obtain();
        g.writeToParcel(parcel, 0);
        parcel.setDataPosition(0);

        NotificationChannelGroup g2
                = mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG_N_MR1, UID_N_MR1);
        Parcel parcel2 = Parcel.obtain();
        g2.writeToParcel(parcel2, 0);
        parcel2.setDataPosition(0);
    }

    @Test
    public void testOnUserRemoved() throws Exception {
        int[] user0Uids = {98, 235, 16, 3782};