我正在为计算机科学的最终论文开发一个应用程序,我需要收集并记录加速度计数据 . 我需要一整天才能获得它,因此存在严重的电池限制(例如,我无法启动屏幕) . 此外,这不是一个以市场为目标的应用程序,因此如果需要,做一些严重的黑客攻击,甚至低级C / C编码是完全可以接受的 .
众所周知,在许多设备上,加速度计事件的监听器在屏幕关闭时停止生成事件(关于此问题的一些链接:http://code.google.com/p/android/issues/detail?id=3708,Accelerometer stops delivering samples when the screen is off on Droid/Nexus One even with a WakeLock) . 我已经彻底搜索了一些替代方案,其中一些包括对我的设备不起作用的解决方法(LG P990,股票ROM) .
所以会发生这样的事情:当您在服务中为Android加速计传感器注册事件监听器时,它可以正常运行,直到屏幕关闭 . 我已经尝试在IntentService上的服务上注册eventListener,试图获取WakeLocks . 关于唤醒锁,我可以验证服务是否仍在运行,观察LOGcat输出,但似乎加速度计进入睡眠模式 . 某些链接中提供的解决方法之一是使用IntentService的线程定期取消注册和重新注册事件侦听器,如下面的代码片段所示
synchronized private static PowerManager.WakeLock getLock(Context context) {
if (lockStatic==null) {
PowerManager mgr=(PowerManager)context.getSystemService(Context.POWER_SERVICE);
lockStatic = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,NAME);
lockStatic.setReferenceCounted(true);
}
return(lockStatic);
}
@Override
protected void onHandleIntent(Intent intent) {
sensorManager=(SensorManager) getSystemService(SENSOR_SERVICE);
sensorManager.unregisterListener(this);
sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
synchronized (this) {
boolean run = true;
while (run){
try {
wait(1000);
getLock(AccelerometerService.this).acquire();
sensorManager=(SensorManager) getSystemService(SENSOR_SERVICE);
sensorManager.unregisterListener(this);
sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
Log.d("Accelerometer service", "tick!");
} catch (Exception e) {
run = false;
Log.d("Accelerometer service", "interrupted; cause: " + e.getMessage());
}
}
}
}
@Override
public void onSensorChanged(SensorEvent event) {
Log.d("accelerometer event received", "xyz: "+ event.values[0] + "," + event.values[1] + "," + event.values[2]);
}
这确实使每次我们取消注册/注册监听器时都会调用onSensorChange . 问题是收到的事件总是包含相同的值,无论我是否摇动设备 .
所以,基本上我的问题是:(忍受我,我差不多完成:P)
-
是否可以对加速计硬件进行低级访问(C / C方法)而无需注册到事件监听器?
-
还有其他解决方法或黑客攻击吗?
如果问题在固件3.0及更高版本中持续存在,那么拥有更新电话的任何人都可以测试一下吗?
[UPDATE]
Unfortunately, it seems to be a bug with some cellphones. More details in my answer.
6 回答
基本上,这是我的手机的问题 . 其他用户报告说,这也适用于他们的手机,来自不同品牌但相同的Android版本 . 其他人完全没有问题 - 强烈表明这不是Android的股票版本的问题,而是来自每家公司的硬件驱动程序的实现 .
我需要提供恒定的加速度计数据,并且不能让加密狗为我测量这些数据 - 我有一个带蓝牙和加速度计的Arduino,所以我可以实现这个解决方案 . 所以我决定手机的临时解决方案是让屏幕亮(变暗)并忽略电池消耗 . 稍后我会使用另一个安卓手机进行电池使用测试,该手机可以关闭屏幕 .
More information about the bug
我已经研究了一些,并发现了其他Android用户的报告,我想也许我明白发生了什么 . 图书馆libsensors.so有手机传感器的驱动程序不是由谷歌开发的,而是由每个手机供应商开发的 - 当然,因为每个手机都有自己的特定硬件 . Google只提供C头文件,以便开发人员知道他们必须实现的内容 . 在这些驱动程序的一些实现中,开发人员只需在屏幕关闭时关闭加速度计,从而阻止传感器事件监听器接收新事件 .
我也用CyanogenMod RC7.2对它进行了测试,但它也没有用,因为加速度计驱动程序是LG的原创 .
E-mails exchanged with HR department of LG
我发了一封电子邮件给LG P990的开发者,最后得到了一些具体的答案!对于像我这样经历Android问题的人来说,这可能会有很大的帮助 . 我写了以下问题
对于我收到的回复:
然后我发回了一封电子邮件,除其他外,我认为这是一个错误,因为在获取唤醒锁时应该有权访问所有硬件:
然后我收到了这个答案:
所以他们显然知道这一点,但并没有试图纠正这个问题,因为要么他们认为这不是一个错误 - 我仍然坚信这是一个逻辑缺陷 - 或者他们没有时间/资源来纠正它 .
Bottom line 如果您的手机在屏幕关闭时未发送加速计事件,请尝试更新固件 . 如果这没有解决,你真的想做一些严重的黑客攻击,重新实现你的硬件层 - 提示:这可能与libsensors.so有关 .
我不确定这是否真的会对你有所帮助,但我找到了一个解决办法(不知道如果能帮助节省电池有多好) .
使用bash我有一个while循环捕获
/sys/devices/virtual/accelerometer/accelerometer/acc_file
,当我通过电源按钮关闭屏幕时输出继续,但被冻结 . (我的sshd在chroot中运行,因此能够看到它 . )但是,在回显
0 > /sys/devices/platform/msm_fb.196609/leds/lcd-backlight/brightness
. 屏幕关闭,输出连续 .这是在SGH-T589W上运行Android 2.3.6版本 .
我应用了PARTIAL_WAKE_LOCK,它对我来说就像魅力一样 . 在OS 5.0,6.0和7.0上测试过 . 这是我获取和释放唤醒锁的代码 . 小心它增加了电池排水,因此智能地获取和释放它 .
参考:https://developer.android.com/training/scheduling/wakelock.html#cpu
我正在研究预测sdk,他使用设备传感器(加速度计/陀螺仪)数据并预测用户事件 . 我遇到了同样的问题 .
我使用其他系统服务运行Android 4.0.2的三星Nexus遇到了类似的问题,即使获得了
PARTIAL_WAKE_LOCK
,屏幕关闭时停止/暂停 . 我的解决方案是使用SCREEN_DIM_WAKE_LOCK
,如:将屏幕完全关闭会好得多,但至少这个解决方案有效,尽管如果我可以将
SCREEN_DIM_WAKE_LOCK
仅限于那些需要它的设备/操作系统,那就更好了 .我讨厌让你失望,但有些设备在睡眠模式下不会保持加速状态 . 有些人这样做,有些则没有 . 您可以检查商店中的任何计步器减肥应用程序,其中大多数明确说明这在某些设备上不起作用 .
如果部分唤醒锁定选项不适用于您的手机,则表示传感器的驱动程序已启用
early_suspend
.有两种选择 .
1:在驱动程序中禁用
EARLY_SUSPEND
2:在驱动程序级别添加一个可以
enable
/disable early_suspend
功能的运行时标志 .恩 . cat / sys / module / earlysuspend / sensor 1/0
IMO第二种选择应该从一开始就存在 .