为啥 NotificationManagerCompat::cancelAll() 得到 SecurityException?
Posted
技术标签:
【中文标题】为啥 NotificationManagerCompat::cancelAll() 得到 SecurityException?【英文标题】:Why NotificationManagerCompat::cancelAll() gets SecurityException?为什么 NotificationManagerCompat::cancelAll() 得到 SecurityException? 【发布时间】:2016-08-06 15:37:29 【问题描述】:使用NotificationManagerCompat
取消所有通知。
NotificationManagerCompat manager =
NotificationManagerCompat.from(ctx.getApplicationContext());
manager.cancelAll();
它有时会出现异常(大部分时间都有效)。
在安卓 6 上:
java.lang.SecurityException: Permission Denial: getCurrentUser() from pid=22994, 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: Permission Denial: getIntentSender() from pid=5460, uid=10135, (need uid=1000) is not allowed to send as package android 在 android.os.Parcel.readException(Parcel.java:1465)
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)
问题:
-
可能是什么原因?
这里的 id 是什么?是
ctx.getApplicationContext().getApplicationInfo().uid
还是android.os.Process.myUid()
?
【问题讨论】:
"是 ctx.getApplicationContext().getApplicationInfo().uid 还是 android.os.Process.myUid()?" -- 对于大多数 Android 应用程序,这些应该是相同的。不过,您的两个错误都很奇怪。 感谢 CommonsWare!很奇怪,它只是使用应用程序的上下文来删除所有通知(从同一个应用程序内部发布),但得到安全异常。可能的原因是什么? 所以我想我得试着抓住这个癌症。 @66CLSjY 我假设,取决于这些pid
和 uid
是否属于您的应用程序,这可能是“活页夹同步”中的错误,例如,getIntentSender()
是使用uid
的Binder
身份调用,而它是使用系统的身份(uid
=1000)调用的,或者在处理您的调用时,其他对象的Binders 使用原始调用者(您的)身份调用而不清除首先它。我想除了捕获问题调用引发的异常之外,您无能为力。
@Onik,这确实揭示了这个问题是如何产生的。谢谢。
【参考方案1】:
答案并没有为问题提供可靠的解决方案,而是试图为提供赏金的 OP 和 @66CLSjY 解释原因, similar issue。
检查堆栈跟踪
根据stacktraceSecurityException
在远程进程中被抛出:你的app进程'Binder
对象(例如INotificationManager.Stub
、ActivityManagerProxy
等)makes a Binder
transaction(mRemote.transact()
)*在远程@ 987654339@ 对象并从对象中读取远程调用中发生的异常 (_reply.readException()
)。如果有的话,你的进程中的exception message is analyzed and a corresponding exception is thrown。
分析异常消息
两个异常消息(一个带有getIntentSender()
,另一个带有getCurrentUser()
)都非常简单——您的应用没有通过权限检查,或者换句话说,ActivityManagerService
的代码 sn-ps本来应该叫under the system_server
process' identity (UID=1000
) **,但实际上叫under your app process' identity。
可能的原因和解决方法
它有时会出现异常(大部分时间都有效)。
如果不做任何假设,你得到的“一段时间”是不恰当的Android
行为。 Wrapping the problem call with try/catch
似乎是一种解决方法,直到有人提出可靠的解决方案(如果存在)。
* ActivityManagerProxy.setRequestedOrientation() 和 IAccessibilityManager$Stub$Proxy.sendAccessibilityEvent() ** android.permission.INTERACT_ACROSS_USERS
属于 signature | system protection level
【讨论】:
【参考方案2】:在我看来,这不起作用有两种不同的可能性:
最可能的原因是您使用错误的上下文进行调用; getApplicationContext()
不是 100% 可靠的,有时会产生奇怪的错误,最好避免这个调用。如果您从 Service 或 Activity 调用 cancelAll()
,请使用 YourClass.this
而不是 getApplicationContext()
,如果它来自 BroadcastReceiver,请使用提供的 Context 变量。
如果这仍然不起作用,则可能是NotificationManagerCompat
中的一个错误,请尝试使用NotificationManager
重现相同的问题。一种解决方法是将所有通知 ID 保存在一个列表中,然后使用 manager.cancel(id)
取消它们。这样系统就不会尝试取消任何不属于您的应用的通知。
【讨论】:
以上是关于为啥 NotificationManagerCompat::cancelAll() 得到 SecurityException?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 DataGridView 上的 DoubleBuffered 属性默认为 false,为啥它受到保护?