WakeLock 相关的 Mandelbug:WakeLock.acquire() 总是成功吗?
问题
我已经为 Android 开发了一段时间了。我开发的程序之一大量使用 WakeLocks 。它通常是完美的(通常一次持续几天或几周,这是程序的要求),但我很少注意到这段代码中的特殊行为:
acquireWakeLock(wakeLockManager)
// Preconditions
assertFalse("Wake lock already acquired.", hasWakeLock());
assertNotNull("Wake lock manager not provided.", wakeLockManager);
// Acquire a wake lock.
wakeLock = wakeLockManager.newPartialWakeLock(DEBUG_TAG);
wakeLock.acquire();
// Postconditions
assertTrue("Wake Lock should be held!", hasWakeLock());
其中 hasWakeLock()
只是返回 的结果(wakeLock != null &&wakeLock.isHeld())
和 wakeLockManager.newPartialWakeLock(DEBUG_TAG)
封装了标准“获取 PowerManager 然后返回唤醒”锁”代码。出于测试目的,断言语句是 JUnit 断言方法,因此我认为我们可以假设它们是正确的。
代码的问题是这样的:最终的断言 - assertTrue(hasWakeLock())
- 似乎每隔几周就会失败一次,而且几乎没有任何解释。这意味着我在这里遇到三个可能的问题:(1) 根本不会从 PowerManager 检索唤醒锁 (2) 我有一个并发问题,该问题在极少数情况下会在后置条件之前但在调用 acquire()
,或者 (3) acquire()
有时会出错。
问题调查
如上所述,我正在调查/已经调查了可能发生的三个潜在问题:
假设 1:唤醒锁未返回:
这是那么我会看到一个空指针异常。不可能是这样的。
假设2:我有一个并发问题:
刚刚对涉及获取和释放wakeLock
的所有地方进行的形式化验证证明强烈让我相信情况并非如此。如果我的证明有错误,那么我可能会遇到并发问题,但它确实很阴险且难以发现。
假设3:WakeLock.acquire()有问题,并且不管文档怎么说,它有时可能无法获取锁:
我不喜欢这个假设,因为对于所有 Android 用户来说,除了我之外,还有某人现在肯定已经注意到这一点,并且几乎总是开发人员的代码有问题,而不是库或操作系统代码。话又说回来,奇怪的事情发生了,这可能是一个真正的 Android 错误,尽管很少出现。如果这个假设成立,那么 acquire() 根本就没有获取唤醒锁,这可以解释我所看到的行为。
那么 StackOverflow,什么可能导致这个问题呢?你觉得哪里不对?我是否遗漏了一些明显的东西,或者这可能是 Android 唤醒锁的真正问题吗?
The Problem
I've been developing for Android for quite some time now. One of the programs I've developed makes heavy use of WakeLocks. It usually perfectly (often for days or weeks at a time, a requirement of the program), but very rarely I notice peculiar behaviour in this code:
acquireWakeLock(wakeLockManager)
// Preconditions
assertFalse("Wake lock already acquired.", hasWakeLock());
assertNotNull("Wake lock manager not provided.", wakeLockManager);
// Acquire a wake lock.
wakeLock = wakeLockManager.newPartialWakeLock(DEBUG_TAG);
wakeLock.acquire();
// Postconditions
assertTrue("Wake Lock should be held!", hasWakeLock());
Where hasWakeLock()
simply returns the result of (wakeLock != null && wakeLock.isHeld())
and wakeLockManager.newPartialWakeLock(DEBUG_TAG)
encapsulates the standard "get the PowerManager and then return a wake lock" code. For the purposes of testing, the assert statements are JUnit assert methods so I think we can assume that they are correct.
The problem with the code is this: the final assertion - assertTrue(hasWakeLock())
- seems to fail every few weeks with very little explanation. It means that I have three possible issues here: (1) the wake lock is never retrieved at all from the PowerManager (2) that I have a concurrency issue that on rare occasions takes effect just before the postcondition but after the call to acquire()
, or that (3) acquire()
is sometimes faulty.
Investigation of the Problem
As stated above, I have three potential issues that may be occurring that I am investigating / have investigated:
Hypothesis 1: Wake Lock not returned:
Were this the case then I would see a null pointer exception. It can't be that.
Hypothesis 2: I have a concurrency issue:
A just-conducted formal verification proof of all places involved in acquiring and releasing wakeLock
strongly leads me to believe that this is not the case. In the case that my proof is faulty then I may have a concurrency issue, but it is then truly insidious and difficult to find.
Hypothesis 3: WakeLock.acquire() is faulty, and despite what the documentation says it sometimes can fail to acquire the lock:
I dislike this hypothesis because with all of the Android users our there someone aside from myself must have noticed this by now and it is almost always the developer's code, not the library or OS code, that is faulty. Then again, stranger things have happened and this might be a genuine Android bug, albeit a rarely exhibited one. If this hypothesis is true then acquire() is simply not acquiring the wake lock and this would explain the behaviour I'm seeing.
So StackOverflow, what could be causing this problem? What do you think is wrong? Am I missing something obvious, or could this be a genuine problem with Android's wake locks?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
看来这确实是一个并发问题。我忽略了一个事实,即可以从单独线程中的非同步位置调用相关方法 - 在高度多线程环境中这是一个明显的问题!
It would appear that this was indeed a concurrency issue. I overlooked the fact that a relevant method could be called from a non-synchronized location in a separate thread - an obvious problem in a highly multithreaded environment!