问题:
java.lang.SecurityException: Disallowed call from unknown notification listener: android.service.notification.INotificationListener$Stub$Proxy@130eeac class android.service.notification.INotificationListener$Stub$Proxy
at android.os.Parcel.createException(Parcel.java:1950)
at android.os.Parcel.readException(Parcel.java:1918)
at android.os.Parcel.readException(Parcel.java:1868)
at android.app.INotificationManager$Stub$Proxy.cancelNotificationsFromListener(INotificationManager.java:2381)
at android.service.notification.NotificationListenerService.cancelNotification(NotificationListenerService.java:590)
at com.app.service.MyNotificationListenerService.deleteNotification(MyNotificationListenerService.java:190)
at com.app.service.MyNotificationListenerService$1.run(MyNotificationListenerService.java:304)
at com.neat.async.TaskQueue.run(TaskQueue.java:41)
Caused by: android.os.RemoteException: Remote stack trace:
at com.android.server.notification.ManagedServices.checkServiceTokenLocked(ManagedServices.java:601)
at com.android.server.notification.NotificationManagerService$11.cancelNotificationsFromListener(NotificationManagerService.java:2844)
at android.app.INotificationManager$Stub.onTransact(INotificationManager.java:665)
at android.os.Binder.execTransact(Binder.java:752)
原因:
调用cancelNotification方法时,如果NotificationListenerService断开连接,就会产生该bug,NotificationListenerService会在授权成功时连接,授权关闭时断开连接,但也会因为一些其他原因导致连接断开,如下:
分析:
根据堆栈信息,在ManagedServices类的checkServiceTokenLocked方法中找到了该bug的出处,如下:
public ManagedServiceInfo checkServiceTokenLocked(IInterface service) {
checkNotNull(service);
final IBinder token = service.asBinder();
final int N = mServices.size();
for (int i=0; i<N; i++) {
final ManagedServiceInfo info = mServices.get(i);
if (info.service.asBinder() == token) return info;
}
throw new SecurityException("Disallowed call from unknown " + getCaption() + ": "
+ service);
}
可以看到,当传进来的参数IInterface不在mServices列表里时,就会产生该bug,在ManagedServices类的mServices属性前有如下注释:
// contains connections to all connected services, including app services
// and system services
protected final ArrayList<ManagedServiceInfo> mServices = new ArrayList<ManagedServiceInfo>();
解决方案:
有上文可知,属性mServices包括所有已连接的服务,所以,我们可以在继承NotificationListenerService的服务中重写onListenerConnected和onListenerDisconnected两个方法,并用一个bool值listenerConnected来标记该服务连接状态,如下:
private boolean listenerConnected;
@Override
public void onListenerConnected() {
super.onListenerConnected();
listenerConnected = true;
}
@Override
public void onListenerDisconnected() {
super.onListenerDisconnected();
listenerConnected = false;
}
然后再调用cancelNotification前先判断连接状态:
if (listenerConnected) {
if (Build.VERSION.SDK_INT >= 21) {
cancelNotification(key);
} else {
cancelNotification(packageName, tag, id);
}
}
网友评论