Merge "Clear calling identity before verifying listeners" into oc-dev

This commit is contained in:
Julia Reynolds
2017-04-12 19:13:01 +00:00
committed by Android (Google) Code Review
2 changed files with 70 additions and 46 deletions

View File

@@ -2695,7 +2695,9 @@ public class NotificationManagerService extends SystemService {
Preconditions.checkNotNull(channel);
ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
checkHasCompanionDevice(info);
if (!hasCompanionDevice(info)) {
throw new SecurityException(info + " does not have access");
}
int uid = mPackageManager.getPackageUid(pkg, 0, info.userid);
updateNotificationChannelInt(pkg, uid, channel, true);
@@ -2705,7 +2707,9 @@ public class NotificationManagerService extends SystemService {
public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
INotificationListener token, String pkg) throws RemoteException {
ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
checkHasCompanionDevice(info);
if (!hasCompanionDevice(info)) {
throw new SecurityException(info + " does not have access");
}
int uid = mPackageManager.getPackageUid(pkg, 0, info.userid);
return mRankingHelper.getNotificationChannels(pkg, uid, false /* includeDeleted */);
@@ -2716,7 +2720,9 @@ public class NotificationManagerService extends SystemService {
getNotificationChannelGroupsFromPrivilegedListener(
INotificationListener token, String pkg) throws RemoteException {
ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
checkHasCompanionDevice(info);
if (!hasCompanionDevice(info)) {
throw new SecurityException(info + " does not have access");
}
List<NotificationChannelGroup> groups = new ArrayList<>();
int uid = mPackageManager.getPackageUid(pkg, 0, info.userid);
@@ -4655,15 +4661,28 @@ public class NotificationManagerService extends SystemService {
channels, overridePeople, snoozeCriteria, showBadge);
}
private void checkHasCompanionDevice(ManagedServiceInfo info) throws RemoteException {
boolean hasCompanionDevice(ManagedServiceInfo info) {
if (mCompanionManager == null) {
mCompanionManager = ICompanionDeviceManager.Stub.asInterface(
ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
}
if (ArrayUtils.isEmpty(mCompanionManager.getAssociations(
info.component.getPackageName(), info.userid))) {
throw new SecurityException("Disallowed call from " + info.component);
long identity = Binder.clearCallingIdentity();
try {
List<String> associations = mCompanionManager.getAssociations(
info.component.getPackageName(), info.userid);
if (!ArrayUtils.isEmpty(associations)) {
return true;
}
} catch (SecurityException se) {
// Not a privileged listener
} catch (RemoteException re) {
Slog.e(TAG, "Cannot reach companion device service", re);
} catch (Exception e) {
Slog.e(TAG, "Cannot verify listener " + info, e);
} finally {
Binder.restoreCallingIdentity(identity);
}
return false;
}
private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
@@ -4996,23 +5015,19 @@ public class NotificationManagerService extends SystemService {
return;
}
for (final ManagedServiceInfo serviceInfo : getServices()) {
if (!serviceInfo.isEnabledForCurrentProfiles()) {
if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
continue;
}
try {
checkHasCompanionDevice(serviceInfo);
mHandler.post(new Runnable() {
@Override
public void run() {
notifyNotificationChannelChanged(serviceInfo, pkg, channel,
modificationType);
}
});
} catch (SecurityException se) {
// Not a privileged listener; do not notify
} catch (RemoteException e) {
Slog.e(TAG, "Cannot reach companion device service", e);
if (!hasCompanionDevice(serviceInfo)) {
continue;
}
mHandler.post(new Runnable() {
@Override
public void run() {
notifyNotificationChannelChanged(serviceInfo, pkg, channel,
modificationType);
}
});
}
}
@@ -5022,23 +5037,19 @@ public class NotificationManagerService extends SystemService {
return;
}
for (final ManagedServiceInfo serviceInfo : getServices()) {
if (!serviceInfo.isEnabledForCurrentProfiles()) {
if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
continue;
}
try {
checkHasCompanionDevice(serviceInfo);
mHandler.post(new Runnable() {
@Override
public void run() {
notifyNotificationChannelGroupChanged(serviceInfo, pkg, group,
modificationType);
}
});
} catch (SecurityException se) {
// Not a privileged listener; do not notify
} catch (RemoteException e) {
Slog.e(TAG, "Cannot reach companion device service", e);
if (!hasCompanionDevice(serviceInfo)) {
continue;
}
mHandler.post(new Runnable() {
@Override
public void run() {
notifyNotificationChannelGroupChanged(serviceInfo, pkg, group,
modificationType);
}
});
}
}

View File

@@ -59,10 +59,11 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
@@ -74,20 +75,21 @@ public class NotificationManagerServiceTest {
private NotificationManagerService mNotificationManagerService;
private INotificationManager mBinderService;
private NotificationManagerInternal mInternalService;
private IPackageManager mPackageManager = mock(IPackageManager.class);
private final PackageManager mPackageManagerClient = mock(PackageManager.class);
@Mock
private IPackageManager mPackageManager;
@Mock
private PackageManager mPackageManagerClient;
private Context mContext = InstrumentationRegistry.getTargetContext();
private final String PKG = mContext.getPackageName();
private TestableLooper mTestableLooper;
private final RankingHelper mRankingHelper = mock(RankingHelper.class);
@Mock
private RankingHelper mRankingHelper;
private NotificationChannel mTestNotificationChannel = new NotificationChannel(
TEST_CHANNEL_ID, TEST_CHANNEL_ID, NotificationManager.IMPORTANCE_DEFAULT);
private NotificationManagerService.NotificationListeners mNotificationListeners =
mock(NotificationManagerService.NotificationListeners.class);
private ManagedServices.ManagedServiceInfo mListener =
mNotificationListeners.new ManagedServiceInfo(
null, new ComponentName(PKG, "test_class"), uid, true, null, 0);
private ICompanionDeviceManager mCompanionMgr = mock(ICompanionDeviceManager.class);
@Mock
private NotificationManagerService.NotificationListeners mNotificationListeners;
private ManagedServices.ManagedServiceInfo mListener;
@Mock private ICompanionDeviceManager mCompanionMgr;
// Use a Testable subclass so we can simulate calls from the system without failing.
private static class TestableNotificationManagerService extends NotificationManagerService {
@@ -102,6 +104,7 @@ public class NotificationManagerServiceTest {
@Before
@UiThreadTest
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mNotificationManagerService = new TestableNotificationManagerService(mContext);
// MockPackageManager - default returns ApplicationInfo with matching calling UID
@@ -116,6 +119,8 @@ public class NotificationManagerServiceTest {
// Use this testable looper.
mTestableLooper = new TestableLooper(false);
mListener = mNotificationListeners.new ManagedServiceInfo(
null, new ComponentName(PKG, "test_class"), uid, true, null, 0);
when(mNotificationListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
mNotificationManagerService.init(mTestableLooper.getLooper(), mPackageManager,
mPackageManagerClient, mockLightsManager, mNotificationListeners, mCompanionMgr);
@@ -631,4 +636,12 @@ public class NotificationManagerServiceTest {
verify(mRankingHelper, never()).getNotificationChannelGroups(anyString(), anyInt());
}
@Test
@UiThreadTest
public void testHasCompanionDevice_failure() throws Exception {
when(mCompanionMgr.getAssociations(anyString(), anyInt())).thenThrow(
new IllegalArgumentException());
mNotificationManagerService.hasCompanionDevice(mListener);
}
}