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

74
我正在开发一份计算机科学的毕业论文应用程序,需要收集和记录加速度计数据。我需要全天候获取数据,因此有严格的电池限制(例如,不能让屏幕开着)。此外,这不是市场定向的应用程序,因此需要进行某些重要的黑客操作,甚至可能需要进行底层的C/C++编码。
众所周知,在许多设备上,当屏幕关闭时,加速度计事件的监听器停止生成事件(关于这个问题的一些链接:http://code.google.com/p/android/issues/detail?id=3708即使使用WakeLock,Droid/Nexus One上的屏幕关闭后加速度计仍将停止传递样本)。我已经彻底搜索了一些替代方案,其中一些包括解决方法,但对我的设备(LG P990,原生ROM)不起作用。
所以问题来了: 当在Service中为Android加速度计传感器注册事件监听器时,它正常工作,直到屏幕关闭。我已经尝试在Service、IntentService上注册eventListener,并尝试获得WakeLocks。关于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)

  1. 是否可能在不注册事件侦听器的情况下访问加速度计硬件(采用C/C++方法)?

  2. 是否有其他解决方法或黑客技巧?

  3. 是否可以请任何使用更新型号手机的人测试一下,在固件3.0及以上版本中问题是否仍然存在?

[更新]

不幸的是,这似乎是一些手机的错误。更多详细信息请参见我的答案。


1
嗨。我刚刚用我的HTC Sensation(ICS)测试了这个问题。即使屏幕关闭,加速度计和磁场传感器仍然持续报告值。此外,您是否已经检查了评论[46]中描述的解决方法?(http://code.google.com/p/android/issues/detail?id=3708) - Renard
1
也许从另一个角度解决问题会更有用——获取屏幕锁定,同时将屏幕亮度降至零以节省电池?当然,当您使用电源按钮关闭屏幕时,它不起作用,但对于这种情况,您可以尝试唤醒设备以防止屏幕锁定。 - Andrey Starodubtsev
1
我最近在多个不同型号的安卓手机上进行了加速度计和磁力计记录,从未遇到过这个问题。我的型号包括几个HTC和一个三星Captivate,所以我想选择范围并不广泛。但是如果这是你的论文,也许暂时与你的朋友交换手机以获取日志是值得的。您还可以考虑使用DIM屏幕wakelock,并更少地记录日志,将手机休眠5分钟,并定期唤醒以获取一些样本。您可以使用AlarmManager和BroadcastReciever来实现。 - mwengler
3
马丁,我认为你已经自己回答了这个问题,所以你应该创建并接受一个答案来回答你的问题,并把所有的发现都放在答案里。 - Renard
1
使用独立的加速度计作为选项,例如由Shimmer Research制造的那些可以通过蓝牙发送数据的加速度计,这是可行的吗?你甚至可以轻松地编写和刷写自己的固件:http://www.shimmer-research.com/ 我自己也曾经使用过它们,并且它们可以工作(并且可以与Android一起使用)---尽管您需要研究它们的电池寿命。 - Thomas Dignan
显示剩余4条评论
6个回答

75
基本上,这是我手机的问题。其他用户也报告了他们的手机出现了同样的问题,来自不同品牌但相同Android版本的手机也有此问题。其他人则没有任何问题-强烈表明这不是Android原始版本的问题,而是每个公司针对其硬件驱动程序的实现问题。
我需要不断提供加速度计数据,并且不能让一个Dongle为我测量这些数据-我有一个带有蓝牙和加速度计的Arduino,因此我可以实施此解决方案。因此,我决定,我的手机的临时解决方法是让屏幕保持开启(调暗),并忽略电池消耗。稍后,我将使用另一部正常工作的Android手机进行电池使用测试,该手机在关闭屏幕时仍然可以使用加速度计。
更多关于漏洞的信息
我进行了更多研究,发现其他Android用户的报告,我认为可能我已经了解发生了什么。用于手机传感器驱动程序的库libsensors.so并非由 Google 开发,而是由每个手机制造商 - 当然,因为每个手机都有自己特定的硬件。Google只提供C头文件,以便开发人员知道他们必须实施什么。对于这些驱动程序的某些实现,开发人员仅在屏幕关闭时关闭加速度计,从而防止传感器事件侦听器接收新事件。
我还尝试了CyanogenMod RC7.2,但它也无法工作,因为加速度计驱动程序是原始的LG。
与LG公司人力资源部门交换的电子邮件
我向LG P990的开发人员发送了电子邮件,并最终得到了一些具体答案!这可能对像我一样遇到Android问题的人非常有帮助。我写了以下问题:

我回复了一封电子邮件,指出当获取唤醒锁时应该可以访问所有硬件,因此我认为这是一个漏洞:

[...] 我之所以提出这个问题是因为我有一些朋友也拥有相同姜饼版本但来自其他手机品牌的Android手机,他们中的一些人报告说,即使屏幕关闭时也会收到加速度计事件。我在一些论坛上读到,这个漏洞——我认为这是一个漏洞,因为当我获取唤醒锁时,我希望进行一些处理——取决于供应商为其手机实现的传感器驱动程序。这些驱动程序是否可以更新或者这个漏洞是否会在某个时候得到修正?这将极大地帮助我开展正在进行中的工作[...]

然后我收到了这个答复:

据我从开发团队了解,那不是一个漏洞。由于硬件结构的限制,它是这部手机的无限制。我们需要重新设计HAL体系结构和设备驱动程序以支持您的请求。但是,正如您所知,由于缺乏资源,这太困难了。我们正在尽我们所能帮助您,但是如我之前所提到的,我们无法支持您的请求。 (Sean Kim)

因此,他们显然知道这个问题,但不打算纠正它,因为他们可能认为这不是一个漏洞——而我仍然坚信这是一个逻辑上的缺陷——或者他们没有时间/资源来纠正它。

底线如果您拥有的手机在屏幕关闭时不发送加速度计事件,请尝试更新固件。如果这不能解决问题,而你真的想要进行一些严肃的黑客工作,请重新实现硬件层-提示:这可能与libsensors.so有关。


2
感谢马丁提供这么完整的信息。我们真正需要的是一份清单,列出哪些手机在屏幕关闭时支持加速度计事件,因为人们可能想在购买前了解这些信息(就像我一样——我需要这个功能)。也许可以创建一个维基页面,由人们测试自己的手机并更新列表。不知道是否已经存在这样的列表? - Fletch
8
好的,我制作了一个清单:http://www.saltwebsites.com/2012/android-accelerometers-screen-off - Fletch
2
非常棒且非常全面的回答。会给超过一个赞👍🏻👍🏻 :) 在某种程度上,您可以通过监听SCREEN_OFF和SCREEN_ON事件、获取新的唤醒锁并重新启动加速度计服务来解决问题。但是,这仅适用于某些手机。 - LambergaR
优秀的问答方式 - Shakeeb Ayaz
越狱可以解决这个漏洞吗? - Amir

7

我不确定这是否实际上能够帮到你,但是我找到了一种解决方法(我不确定它对电池节省有多大帮助)。

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

然而,在echo 0 > /sys/devices/platform/msm_fb.196609/leds/lcd-backlight/brightness之后,屏幕就会关闭,输出是连续的。

这是在运行安卓版本2.3.6的SGH-T589W设备上的情况。


哎呀!干得好,我没想到可以用Bash脚本..虽然我已经很久以前完成了这项工作,但我想我会尝试一下的。 感谢您的建议! - martin

4

我使用了PARTIAL_WAKE_LOCK,这对我非常有效。在5.0、6.0和7.0的操作系统上进行了测试。这是获取和释放wake lock的代码。要小心,它会增加电池消耗,因此要明智地获取和释放。

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,该 SDK 使用设备传感器(加速度计/陀螺仪)数据并预测用户事件。我遇到了同样的问题。


3

我曾经在三星Nexus上遇到类似的问题,当屏幕关闭时,即使已经获取了PARTIAL_WAKE_LOCK,其他系统服务仍然会停止/暂停。我的解决方案是使用SCREEN_DIM_WAKE_LOCK,如下所示:

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

最好让屏幕完全关闭,但这种解决方案至少可行,虽然如果我可以仅将 SCREEN_DIM_WAKE_LOCK 限制在需要它的设备/操作系统上,那就更好了。


1

很抱歉让你失望,但有些设备在睡眠模式下不会保持加速度计的运行。有些设备可以,而有些则不行。你可以检查商店中的任何计步器减肥应用程序,其中大多数明确说明这在某些设备上无法使用。


1

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

有两个选项。

1:在驱动程序中禁用EARLY_SUSPEND

2:添加一个运行时标志,可以在驱动程序级别上启用/禁用early_suspend功能。

例如:cat /sys/module/earlysuspend/sensor 1/0

我认为第二个选项应该从一开始就存在。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接