当屏幕关闭时,Android 加速计无法工作

我正在为我的计算机科学毕业论文开发一个应用程序,我需要收集和记录加速度计数据。我需要一整天的时间来使用它,所以有严重的电池限制(例如,我不能让屏幕一直开着)。此外,这不是一个针对市场的应用程序,所以做一些严重的黑客行为是可以接受的,即使是低级的 C/C + + 编码,如果需要的话。

众所周知,在许多设备上,当屏幕关闭时,加速计事件的监听器停止生成事件(关于这个问题的一些链接: http://code.google.com/p/android/issues/detail?id=3708当 Droid/Nexus One 上的屏幕关闭时,加速度计就会停止传送样品,即使它带有 WakeLock)。我已经彻底搜索了一些替代方案,其中一些包括工作区,不适合我的设备(LG P990,股票 ROM)。

事情是这样的: 当您为服务中的 android 加速计传感器注册一个事件侦听器时,它工作得很好,直到屏幕关闭。我已经尝试在服务上注册事件监听器,在意图服务上尝试获取 WakeLocks。关于 wakelocks,我可以验证服务是否仍在运行,观察 LOGcat 的输出,但似乎加速计进入了睡眠模式。一些链接中提供的变通方法之一是使用 InentService 的线程定期取消注册并重新注册事件侦听器,如下面的代码片段所示

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)

  1. 是否有可能对加速计硬件进行低级访问(C/C + + 方法)而不需要向事件侦听器注册?

  2. 还有别的解决办法或者黑客技术吗?

  3. 如果问题在3.0及以上版本的固件中仍然存在,是否有人可以使用更新的手机进行测试?

[更新]

不幸的是,这似乎是一些手机的错误。更多细节在我的回答。

27119 次浏览

我不想让你失望,但是有些设备在睡眠模式下不能保持加速器运行。有些会,有些不会。你可以检查任何计步器减肥应用程序商店他们中的大多数明确声明,这不会在一些设备上工作。

基本上,这是我手机的问题。其他用户报告说,这种情况也发生在他们的手机上,来自不同的品牌,但 Android 版本相同。其他人完全没有问题-强烈表明这不是安卓的股票版本的问题,而是来自每个公司的硬件驱动程序的实现。

我需要不断的加速度计数据传递,不能有一个狗测量这个数据为我-我有一个 Arduino 与蓝牙和加速度计,所以我可以实现这个解决方案。因此,我决定暂时解决我的手机是让屏幕上(调暗)和忽略电池消耗。稍后,我将使用另一款屏幕关闭的 Android 手机执行电池使用测试。

更多关于错误的信息

我研究了一些其他 Android 用户的报告,我想我可能知道发生了什么。手机传感器的驱动程序不是由谷歌开发的,而是由每个手机供应商开发的——当然,因为每个手机都有自己特定的硬件。Google 只提供了一个 C 头文件,让开发人员知道他们必须实现什么。在这些驱动程序的某些实现中,开发人员只需在屏幕关闭时关闭加速计,从而阻止传感器事件监听器接收新事件。

我也用 CyanogenMod RC7.2测试了这个,但是它也没有工作,因为加速计驱动程序是 LG 的原创。

与 LG 人力资源部的电子邮件往来

我给 LG P990的开发者发了一封电子邮件,终于得到了一些具体的答案!对于像我这样在 Android 上遇到这些问题的人来说,这可能会有很大的帮助。我写了下面的问题

你好! 我正在发展我的计算机科学的论文,目前我 我正在从加速计硬件中获取数据。到目前为止,我发现 当屏幕关闭时,加速度计不会发送事件,所以 即使我从我的程序中抓取了一个尾锁,我也可以 验证我的程序是否仍在运行(通过 LOGcat 输出) ,但是没有 加速度计事件出来。我必须调暗我的屏幕上(我 负担不起,电池耗尽太快)开始接收 我还尝试通过原生 C 访问它 代码,在加速计事件上注册,但结果是 同样,加速度计没有抛出任何值,即使我 转动我的设备,所以我想知道我能不能直接进入 使用本机代码连接到硬件,而不必注册到 听众。这可能吗? 如果可能的话,你能不能再说一些 我会非常感激任何帮助! 马丁

因为我收到了这样的回复:

亲爱的 Martin 我们收到了 Dev 团队的回复,他们说 当你的手机屏幕关闭时不能得到加速度计事件。因为 HAL 层没有实现 sysFS 路径来获取 H/W 事件,例如 没有公共 API 来获得事件。谢谢。最好的 问候。(金尚恩)

然后我发回了一封电子邮件,其中说,我认为这是一个 bug,因为在获取唤醒锁时,应该可以访问所有的硬件:

我问这个问题是因为我有一些朋友 安卓手机有着相同的姜饼版本,但是来自其他版本 手机品牌,其中一些报告说,他们收到的事件从 当屏幕关闭的时候加速度计。我读了一些 论坛,这个错误-我认为它是一个错误,因为当我获得一个 Wakelock 我希望有一些处理正在进行-取决于 供应商为他们的手机实现的传感器驱动程序 有任何可能性,这些驱动程序可以更新或将这 在某个时候修正错误? 这将极大地帮助我的 正在进行的工作[ ... ]

然后我收到了这样的回答:

根据我从 Dev 团队得到的信息,那不是错误,那是无限的 我们需要重新设计 HAL 架构和设备驱动程序来支持您的请求 我们知道由于缺乏资源,这太困难了。我们正在努力 帮助你我们的一切努力,但我们不能支持你的要求,因为我 (金尚恩)

因此,他们显然知道这一点,但没有试图纠正这一点,因为他们要么不认为这是一个错误——我仍然坚信这是一个逻辑缺陷——要么他们没有时间/资源来纠正它。

总之 如果你的手机没有关闭屏幕发送加速度计事件,尝试更新你的固件。如果这个问题没有解决,并且您真的想做一些严重的黑客行为,那么重新实现您的硬件层提示: 它可能与 libsensors.so 有关。

我曾经遇到过类似的问题,三星的 Nexus 运行 Android 4.0.2使用其他系统服务,停止/暂停,而屏幕关闭,即使一个 PARTIAL_WAKE_LOCK是获得。我的解决方案是使用 SCREEN_DIM_WAKE_LOCK,比如:

 lockStatic = mgr.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK,NAME);

屏幕完全关闭会更好,但至少这个解决方案可以工作,如果我可以限制使用 SCREEN_DIM_WAKE_LOCK仅限于那些需要它的设备/操作系统,那就更好了。

我不知道这是否真的会帮助你,但我已经找到了一个周围的工作(不知道如何好,如果将帮助节省电池)。

使用 bash 我有一个 while 循环猫化 /sys/devices/virtual/accelerometer/accelerometer/acc_file,当我通过电源按钮关闭屏幕时,输出继续,但是被冻结。(我在 chroot 中运行 sshd,因此可以看到它。)

但是,在回声 0 > /sys/devices/platform/msm_fb.196609/leds/lcd-backlight/brightness。屏幕关闭,输出是连续的。

这是在 SGH-T589W 上,运行安卓版本2.3.6。

如果部分唤醒锁定选项不可用于您的手机,这意味着传感器的驱动程序启用了 early_suspend

有两个选择。

1: 禁用驱动程序中的 EARLY_SUSPEND

2: 添加一个可以在驱动程序级别上实现 enable/disable early_suspend功能的运行时标志。

例如 cat/sys/module/earlyspend/Sensor 1/0

国际海事组织的第二选择应该从一开始就存在。

我应用了 PARTIAL _ WAKE _ LOCK,它对我来说非常有效。在 OS 5.0,6.0和7.0上测试。这是我获取和释放唤醒锁的代码。小心它增加了电池排水,所以获取和释放它的智能。

public void acquireWakeLock() {
final PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
releaseWakeLock();
//Acquire new wake lock
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PARTIAL_WAKE_LOCK");
mWakeLock.acquire();
}


public void releaseWakeLock() {
if (mWakeLock != null && mWakeLock.isHeld()) {
mWakeLock.release();
mWakeLock = null;
}
}

档号: https://developer.android.com/training/scheduling/wakelock.html#cpu

我正在开发一个预测 sdk,它使用设备传感器(加速度计/陀螺仪)数据并预测用户事件。我也遇到过同样的问题。