为什么NotificationManagerCompat :: cancelAll()获取SecurityException?

使用NotificationManagerCompat取消所有通知。

 NotificationManagerCompat manager = NotificationManagerCompat.from(ctx.getApplicationContext()); manager.cancelAll(); 

它有一段时间exception(大部分时间都有效)。

在Andoid 6上:

java.lang.SecurityException:Permission Denial:来自pid = 22994的getCurrentUser(),uid = 10184需要android.permission.INTERACT_ACROSS_USERS

 Fatal Exception: java.lang.SecurityException: Permission Denial: getCurrentUser() from pid=22994, uid=10184 requires android.permission.INTERACT_ACROSS_USERS at android.os.Parcel.readException(Parcel.java:1602) at android.os.Parcel.readException(Parcel.java:1555) at android.app.INotificationManager$Stub$Proxy.cancelAllNotifications(INotificationManager.java:649) at android.app.NotificationManager.cancelAll(NotificationManager.java:323) at android.support.v4.app.NotificationManagerCompat.cancelAll(NotificationManagerCompat.java:197) 

在Android 5.0,4.4.2上:

ava.lang.SecurityException:权限拒绝:来自pid = 5460的getIntentSender(),uid = 10135,(需要uid = 1000)不允许在android.os.Parcel.readException(Parcel.java:1465)中作为包android发送

 Fatal Exception: java.lang.SecurityException: Permission Denial: getIntentSender() from pid=3109, uid=10153, (need uid=1000) is not allowed to send as package android at android.os.Parcel.readException(Parcel.java:1472) at android.os.Parcel.readException(Parcel.java:1426) at android.app.INotificationManager$Stub$Proxy.cancelAllNotifications(INotificationManager.java:271) at android.app.NotificationManager.cancelAll(NotificationManager.java:220) at android.support.v4.app.NotificationManagerCompat.cancelAll(NotificationManagerCompat.java:197) 

问题:

  1. 可能是什么原因?
  2. 那里的id是什么? 是ctx.getApplicationContext().getApplicationInfo().uid还是android.os.Process.myUid()

Solutions Collecting From Web of "为什么NotificationManagerCompat :: cancelAll()获取SecurityException?"

答案并没有为问题提供可靠的解决方案 ,而是试图解释OP和提供赏金的@ 66CLSjY的原因 ,并提出类似的问题 。


检查堆栈跟踪

根据stacktrace,在远程进程中抛出SecurityException :你的app进程’ Binder对象(例如INotificationManager.StubActivityManagerProxy等)在远程Binder对象上创建一个Binder事务 ( mRemote.transact() )*并从对象中读取远程调用中发生exception( _reply.readException() )。 如果有, 则分析exception消息并在您的进程中抛出相应的exception 。

分析exception消息

两个exception消息(一个带有getIntentSender() ,另一个带有getCurrentUser() )非常简单 – 你的应用程序没有通过权限检查,换句话说,应该在下面调用的ActivityManagerService的代码片段。 system_server进程’身份 ( UID=1000 )**,但实际上是在您的应用程序进程的身份下调用的。

可能的原因和解决方法

它有一段时间exception(大部分时间都有效)。

没有做出假设,你得到的“一段时间”是不正确的Android行为。 用try/catch包装问题调用似乎是一种解决方法,直到有人建议一个可靠的解决方案(如果存在)。


* ActivityManagerProxy.setRequestedOrientation()和IAccessibilityManager $ Stub $ Proxy.sendAccessibilityEvent()
** android.permission.INTERACT_ACROSS_USERS是签名| 系统保护等级

对我而言,听起来有两种不同的可能性,为什么这不起作用:

最可能的原因是您使用错误的上下文进行呼叫; getApplicationContext()不是100%可靠,有时会产生奇怪的错误,最好避免这个调用。 如果从Service或Activity调用cancelAll() ,请使用YourClass.this而不是getApplicationContext() ,如果它来自BroadcastReceiver,请使用提供的Contextvariables。

如果这仍然无效,则可能是NotificationManagerCompat的错误,请尝试使用NotificationManager重现相同的问题。 解决方法是将所有通知ID保存在列表中,然后使用manager.cancel(id)取消它们。 这样,系统就不会尝试取消任何不属于您的应用的通知。