web-dev-qa-db-ja.com

Android画面がオフのときに加速度計が機能しない

コンピューターサイエンスに関する最終論文のアプリケーションを開発しています。加速度計データを収集して記録する必要があります。私は一日中それを取得する必要があるため、深刻なバッテリーの制約があります(たとえば、画面をオンのままにできません)。また、これは市場をターゲットとしたアプリケーションではないため、必要に応じて、低レベルのC/C++コーディングであっても、深刻なハッキングを行うことはかなり受け入れられます。

多くのデバイスでは、画面が消えると加速度計イベントのリスナーがイベントの生成を停止することがよく知られています(この問題に関するリンク: http://code.google.com/p/Android/issues/detail?id = 3708Droid/Nexus OneでWakeLockを使用していても画面がオフの場合、加速度計はサンプルの配信を停止します )。いくつかの代替案を徹底的に検索しましたが、その中には私のデバイスでは動作しない回避策が含まれています(LG P990、ストックROM)。

つまり、これは次のようになります。サービスのAndroid加速度センサーにイベントリスナーを登録すると、画面がオフになるまで正常に機能します。サービスにeventListenerを登録しようとしました。 、IntentServiceで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が呼び出されます。問題は、デバイスを振っても、受信したイベントには常に同じ値が含まれることです。

したがって、基本的に私の質問は次のとおりです。

  1. イベントリスナーに登録せずに加速度計ハードウェアに低レベルでアクセスすることは可能ですか?

  2. 他の回避策やハッキングはありますか?

  3. 最新の電話をお持ちの方は、ファームウェア3.0以降でも問題が解決するかどうかを親切にテストできますか?

[更新]

残念ながら、一部の携帯電話にはバグがあるようです。私の答えの詳細

67
martin

基本的に、それは私の電話の問題です。他のユーザーは、同じブランドAndroidバージョン。同じバージョンです。他の人はまったく問題ありません。これは=のストックバージョンでは問題ではないことを強く示します。 Androidただし、各社のハードウェアドライバーの実装から。

一定の加速度計データを配信する必要があり、このデータをドングルで測定することはできません。Bluetoothと加速度計を備えたArduinoがあるため、このソリューションを実装できました。そこで、携帯電話の一時的な解決策は、画面をオン(暗く)にして、バッテリーの消費を無視することだと判断しました。後で、画面をオフにして動作する別のAndroid電話を使用して、バッテリー使用量のテストを実行します。

バグに関する詳細情報

私はもう少し調べて、他のAndroidユーザーからのレポートを見つけました。何が起きているのか理解できると思います。電話センサーのドライバーを備えたライブラリlibsensors.soはGoogleによって開発されていません。もちろん、各携帯電話には独自のハードウェアが搭載されているため、Googleは開発者が実装する必要があるものを知るためにCヘッダーファイルのみを提供します。これらのドライバーの実装によっては、開発者は単に加速度計をオフにします画面がオフになると、センサーイベントリスナーが新しいイベントを受信できなくなります。

これをCyanogenMod RC7.2でもテストしましたが、加速度センサードライバーはLG製であるため、どちらも機能しませんでした。

LGの人事部と交換したメール

私はLG P990の開発者に電子メールを送信し、最終的にいくつかの具体的な回答を得ました!これは、Androidでこれらの問題を経験している私のような人々にとって大きな助けになるかもしれません。次の質問

こんにちは!私はコンピューターサイエンスの論文を作成しており、現在、加速度計ハードウェアからデータを取得しています。今のところ、画面がオフのときに加速度計がイベントを送信しないことがわかったので、プログラムの1つからウェイクロックを取得しても、プログラムがまだ実行されていることを確認できます(LOGcat出力を介して)加速度計イベントが出てきます。加速度計のイベントの受信を再開するには、画面を暗くする必要があります(余裕がありません。バッテリーの消耗が速すぎます)。また、ネイティブCコードからアクセスして、加速度計イベントに登録しようとしましたが、結果は同じで、デバイスを回転させても加速度計は値をスローしませんでした。そのため、リスナーに登録することなく、ネイティブコードを使用してハードウェアに直接アクセスできるかどうか疑問に思いました。これは可能ですか?もしそうなら、親切にいくつかのアドバイスをお願いできますか?私はどんな助けも大歓迎です!マーティン

この応答を受け取った場合:

親愛なるマーティン、開発者から回答を受け取りました。チーム。電話画面がオフのときは加速度計イベントを取得できないと彼らは言った。 HALレイヤーは、加速度計などのH/Wイベントを取得するsysFSパスを実装しておらず、イベントを取得するパブリックAPIがないためです。ありがとうございました。宜しくお願いします。 (キム・ショーン)

次に、ウェークロックを取得するときにすべてのハードウェアにアクセスできるようにする必要があるため、これをバグと見なしたことを言って、メールを送り返しました。

[...]この質問は、同じジンジャーブレッドバージョンを持ち、他のブランドの携帯電話を使用しているAndroid電話もあり、加速度計からイベントを受け取ると報告した友人もいるためです。いくつかのフォーラムでこのバグを読みました-Wakelockを取得すると処理が行われると予想されるため、バグだと思います-ベンダーが携帯電話に実装するセンサードライバーに依存する。これらのドライバーを更新できる可能性はありますか、またはこのバグはある時点で修正されますか?これは、進行中の作業で非常に役立ちます[...]

そして、私はこの答えを受け取りました:

開発からの私の知識では。チーム、それはバグではありません。 H/Wアーキテクチャのため、これはこの携帯電話に限りがありません。 HALアーキテクチャとデバイスドライバーを再設計して、要求をサポートする必要があります。しかし、ご存知のように、これはリソース不足のため非常に困難です。私たちはすべての努力であなたを助けようとしていますが、私が述べたようにあなたの要求をサポートすることはできません。 (キム・ショーン)

したがって、彼らは明らかにこれについて知っていますが、それがバグだとは思わないのでこれを修正しようとはしていません-私はまだそれが論理的な欠陥だと強く信じています-または彼らはそれを修正する時間/リソースを持っていません.

下の行画面がオフの状態で加速度計イベントを送信しない携帯電話がある場合は、ファームウェアを更新してみてください。これで解決せず、本当に深刻なハッキングを実行したい場合は、ハードウェアレイヤーを再実装してください-ヒント:おそらくlibsensors.soと関係があるでしょう。

66
martin

これが実際にあなたを助けるかどうかはわかりませんが、回避策を見つけました(バッテリーの節約に役立つかどうかはわかりません)。

Bashを使用して、whileループcat-ing /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を実行しています。

6
fu-fu

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#cp

デバイスセンサー(加速度計/ジャイロスコープ)データを使用してユーザーイベントを予測する予測SDKを作成しています。同じ問題が発生しました。

2
Farhan

サムスンネクサスの実行中に同様の問題に遭遇しましたAndroid 4.0.2PARTIAL_WAKE_LOCKが取得されます。私の解決策は、SCREEN_DIM_WAKE_LOCKのように:

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

画面を完全にオフにする方がはるかに優れていますが、少なくともこのソリューションは機能しますが、SCREEN_DIM_WAKE_LOCK必要なデバイス/ OSのみ。

2
Greg Martin

私はあなたを失望させたくはありませんが、一部のデバイスは、スリープモードにある間は加速度計をオンにしないだけです。ある人はそう、そうでない人はいます。ストアで歩数計の減量アプリを確認できます。ほとんどのアプリでは、一部のデバイスでは機能しないことが明示的に記載されています。

0
EvilDuck

電話機で部分的なウェイクロックオプションが利用できない場合、センサーのドライバーでearly_suspendが有効になっていることを意味します。

2つのオプションがあります。

1:ドライバーでEARLY_SUSPENDを無効にします

2:ドライバーレベルでenable/disable early_suspend機能を実行できるランタイムフラグを追加します。

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

IMO 2番目のオプションは最初からそこにあるはずでした。

0
boosth