Fixed
Status Update
Comments
ks...@google.com <ks...@google.com> #2
Andreas, are you the correct person to investigate here?
as...@google.com <as...@google.com> #4
This is interesting. The rotation vector (or any sensor for that matter) should not perform differently from the Java API at the native API. Villus, I could not access the video on the bug you linked to. Can you please attach it to this bug ?
vi...@unity3d.com <vi...@unity3d.com> #5
Sure, no problem - attaching the videos here.
ks...@google.com <ks...@google.com>
ks...@google.com <ks...@google.com> #6
Ashutosh, have you had a chance to take a look here?
fr...@google.com <fr...@google.com> #7
On Pixel 2 `adb logcat` reports its using 200000us sampling period.
This is 5Hz (SENSOR_DELAY_NORMAL), instead of the desired/expected 50Hz (SENSOR_DELAY_GAME).
01-10 16:14:10.800 794 820 D CHRE : @ 2685.808: +: id 10, otherClientPresent 1, mode 3
01-10 16:14:10.803 794 820 D CHRE : @ 2685.811: [ImuCal] Dynamic sensor configuration: high-performance.
01-10 16:14:10.803 794 820 D CHRE : @ 2685.811: sensorType 9 allowed 1: mergedMode 3, otherClientPresent 1
01-10 16:14:10.803 794 820 I VSC : @ 2685.811: [VSC SLPI] VscSensor type 65545: Enabling with report period 0 and sampling period 200000000
01-10 16:14:10.803 794 820 I VSC : @ 2685.811: {Fusion} configure fusion 9 200000us 0us.
01-10 16:14:10.804 794 820 I VSC : @ 2685.811: [VSC] Request sensor 65537, sample_duration 14 ms, report_duration 0 ms
01-10 16:14:10.804 794 820 I VSC : @ 2685.812: [VSC] Request sensor 65540, sample_duration 5 ms, report_duration 0 ms
01-10 16:14:10.805 794 820 D CHRE : @ 2685.812: sensorType 11 allowed 1: mergedMode 3, otherClientPresent 1
01-10 16:14:10.807 794 820 D CHRE : @ 2685.815: sensorType 13 allowed 0: mergedMode 3, otherClientPresent 0
01-10 16:14:10.810 794 820 I VSC : @ 2685.818: [VSC SLPI] VscSensor type 65546: Enabling with report period 0 and sampling period 200000000
01-10 16:14:10.811 794 820 I VSC : @ 2685.818: {Fusion} configure fusion 10 200000us 0us.
01-10 16:14:10.811 794 820 I VSC : @ 2685.818: [VSC] Request sensor 65537, sample_duration 14 ms, report_duration 0 ms
01-10 16:14:10.811 794 820 I VSC : @ 2685.819: [VSC] Request sensor 65540, sample_duration 5 ms, report_duration 0 ms
01-10 16:14:10.814 794 820 I VSC : @ 2685.822: [VSC SLPI] VscSensor type 65547: Enabling with report period 0 and sampling period 200000000
01-10 16:14:10.815 794 820 I VSC : @ 2685.822: {Fusion} configure fusion 11 200000us 0us.
01-10 16:14:10.815 794 820 I VSC : @ 2685.823: [VSC] Request sensor 65537, sample_duration 14 ms, report_duration 0 ms
01-10 16:14:10.816 794 820 I VSC : @ 2685.824: [VSC] Request sensor 65540, sample_duration 5 ms, report_duration 0 ms
01-10 16:14:10.816 794 820 I VSC : @ 2685.824: [VSC] Request sensor 65538, sample_duration 14 ms, report_duration 0 ms
This is 5Hz (SENSOR_DELAY_NORMAL), instead of the desired/expected 50Hz (SENSOR_DELAY_GAME).
01-10 16:14:10.800 794 820 D CHRE : @ 2685.808: +: id 10, otherClientPresent 1, mode 3
01-10 16:14:10.803 794 820 D CHRE : @ 2685.811: [ImuCal] Dynamic sensor configuration: high-performance.
01-10 16:14:10.803 794 820 D CHRE : @ 2685.811: sensorType 9 allowed 1: mergedMode 3, otherClientPresent 1
01-10 16:14:10.803 794 820 I VSC : @ 2685.811: [VSC SLPI] VscSensor type 65545: Enabling with report period 0 and sampling period 200000000
01-10 16:14:10.803 794 820 I VSC : @ 2685.811: {Fusion} configure fusion 9 200000us 0us.
01-10 16:14:10.804 794 820 I VSC : @ 2685.811: [VSC] Request sensor 65537, sample_duration 14 ms, report_duration 0 ms
01-10 16:14:10.804 794 820 I VSC : @ 2685.812: [VSC] Request sensor 65540, sample_duration 5 ms, report_duration 0 ms
01-10 16:14:10.805 794 820 D CHRE : @ 2685.812: sensorType 11 allowed 1: mergedMode 3, otherClientPresent 1
01-10 16:14:10.807 794 820 D CHRE : @ 2685.815: sensorType 13 allowed 0: mergedMode 3, otherClientPresent 0
01-10 16:14:10.810 794 820 I VSC : @ 2685.818: [VSC SLPI] VscSensor type 65546: Enabling with report period 0 and sampling period 200000000
01-10 16:14:10.811 794 820 I VSC : @ 2685.818: {Fusion} configure fusion 10 200000us 0us.
01-10 16:14:10.811 794 820 I VSC : @ 2685.818: [VSC] Request sensor 65537, sample_duration 14 ms, report_duration 0 ms
01-10 16:14:10.811 794 820 I VSC : @ 2685.819: [VSC] Request sensor 65540, sample_duration 5 ms, report_duration 0 ms
01-10 16:14:10.814 794 820 I VSC : @ 2685.822: [VSC SLPI] VscSensor type 65547: Enabling with report period 0 and sampling period 200000000
01-10 16:14:10.815 794 820 I VSC : @ 2685.822: {Fusion} configure fusion 11 200000us 0us.
01-10 16:14:10.815 794 820 I VSC : @ 2685.823: [VSC] Request sensor 65537, sample_duration 14 ms, report_duration 0 ms
01-10 16:14:10.816 794 820 I VSC : @ 2685.824: [VSC] Request sensor 65540, sample_duration 5 ms, report_duration 0 ms
01-10 16:14:10.816 794 820 I VSC : @ 2685.824: [VSC] Request sensor 65538, sample_duration 14 ms, report_duration 0 ms
fr...@google.com <fr...@google.com> #8
If I replace:
ASensorEventQueue_enableSensor(sSensorEventQueue, sensor);
ASensorEventQueue_setEventRate(sSensorEventQueue, sensor, 20000);
with:
success = ASensorEventQueue_registerSensor(sSensorEventQueue, sensor, 20000, 0);
in `Sensors.cpp` in the above `AndroidGyroNDK.zip` project, then sensors appear to update at the expected rate.
ASensorEventQueue_enableSensor(sSensorEventQueue, sensor);
ASensorEventQueue_setEventRate(sSensorEventQueue, sensor, 20000);
with:
success = ASensorEventQueue_registerSensor(sSensorEventQueue, sensor, 20000, 0);
in `Sensors.cpp` in the above `AndroidGyroNDK.zip` project, then sensors appear to update at the expected rate.
vi...@unity3d.com <vi...@unity3d.com> #9
Nice find, but it seems that this workaround requires the min sdk version to be at least 26, which would exclude a lot of phones.
fr...@google.com <fr...@google.com> #10
Acknowledged.
The fact that `ASensorEventQueue_registerSensor(sSensorEventQueue, sensor, 20000, 0)` works demonstrates that the sensor can provide updates at 50Hz via native code.
So, now we need to get the older API variant to work:
ASensorEventQueue_enableSensor(sSensorEventQueue, sensor);
ASensorEventQueue_setEventRate(sSensorEventQueue, sensor, 20000);
As best I can tell, that second line is not actually doing anything.
The fact that `ASensorEventQueue_registerSensor(sSensorEventQueue, sensor, 20000, 0)` works demonstrates that the sensor can provide updates at 50Hz via native code.
So, now we need to get the older API variant to work:
ASensorEventQueue_enableSensor(sSensorEventQueue, sensor);
ASensorEventQueue_setEventRate(sSensorEventQueue, sensor, 20000);
As best I can tell, that second line is not actually doing anything.
as...@google.com <as...@google.com> #11
Thanks Fred. Do you mind if we pick this up after the Android FC & Bootcamp (2/9) ?
fr...@google.com <fr...@google.com> #12
Any update here?
fr...@google.com <fr...@google.com>
bd...@google.com <bd...@google.com>
bd...@google.com <bd...@google.com> #13
Thank you for the thorough report with test app (and your patience).
In the Pixel 2 case, this is a bug in the sensor HAL implementation for certain sensor types, where the device is unable to properly change the sampling rate after the sensor has been enabled. Since the pre-26 NDK API only allows for enabling a sensor with a default rate, this bug means that the subsequent call to ASensorEventQueue_setEventRate has no effect, so unfortunately there is no workaround possible in pure native code. Although I can't dig into the inner workings of other devices, I suspect it's the same issue there as well (in the Pixel 2 case the issue lies in integration with code supplied by a prominent chipset vendor).
I can think of two ways to work around this issue:
1. Use ASensorEventQueue_registerSensor only on devices running API 26+. To avoid link-time issues when running on an older platform that doesn't provide this function, you can access it through dlsym() like so:
#include <dlfcn.h>
typedef int (NDK_registerSensorFunction)(
ASensorEventQueue *queue, int32_t samplingPeriodUs, int64_t maxBatchReportLatency);
if (<API level >= 26>) {
void *handle = dlopen("libandroid.so", RTLD_LAZY);
if (handle != NULL) {
NDK_registerSensorFunction *registerSensor = (NDK_registerSensorFunction *)
dlsym(handle, "ASensorEventQueue_registerSensor");
if (fptr != NULL) {
registerSensor(queue, samplingPeriod, 0);
}
// probably want to call dlclose() too
}
}
2. Like in the comments from your sample application, add a Java-level request for the sensor before initializing the NDK sensor request. There can only be 1 effective sampling rate for a sensor, which is always the fastest of all open requests. So assuming that no other app is already asking for the sensor, this will guarantee that the sensor is enabled with the rate you want, and the NDK client will get updates at the intended rate. This workaround should avoid the issue on pre-API 26 devices as well, but it imposes some overhead - you might be able to avoid leaving the Java client enabled with a flow like this (haven't tested this but should work in theory):
a. Enable sensor from Java at expected rate (e.g. 200Hz)
b. Enable sensor at NDK (with default rate)
c. Set event rate in NDK to rate matching (a)
d. Disable Java request
Hopefully you'll be able to use one of these two approaches to address the issue for devices in the wild. I'll also look into fixing the root cause in Pixel 2, plus notify the chipset vendor, and see about adding new CTS tests to ensure that future/upgrading devices are not afflicted by this problem.
In the Pixel 2 case, this is a bug in the sensor HAL implementation for certain sensor types, where the device is unable to properly change the sampling rate after the sensor has been enabled. Since the pre-26 NDK API only allows for enabling a sensor with a default rate, this bug means that the subsequent call to ASensorEventQueue_setEventRate has no effect, so unfortunately there is no workaround possible in pure native code. Although I can't dig into the inner workings of other devices, I suspect it's the same issue there as well (in the Pixel 2 case the issue lies in integration with code supplied by a prominent chipset vendor).
I can think of two ways to work around this issue:
1. Use ASensorEventQueue_registerSensor only on devices running API 26+. To avoid link-time issues when running on an older platform that doesn't provide this function, you can access it through dlsym() like so:
#include <dlfcn.h>
typedef int (NDK_registerSensorFunction)(
ASensorEventQueue *queue, int32_t samplingPeriodUs, int64_t maxBatchReportLatency);
if (<API level >= 26>) {
void *handle = dlopen("libandroid.so", RTLD_LAZY);
if (handle != NULL) {
NDK_registerSensorFunction *registerSensor = (NDK_registerSensorFunction *)
dlsym(handle, "ASensorEventQueue_registerSensor");
if (fptr != NULL) {
registerSensor(queue, samplingPeriod, 0);
}
// probably want to call dlclose() too
}
}
2. Like in the comments from your sample application, add a Java-level request for the sensor before initializing the NDK sensor request. There can only be 1 effective sampling rate for a sensor, which is always the fastest of all open requests. So assuming that no other app is already asking for the sensor, this will guarantee that the sensor is enabled with the rate you want, and the NDK client will get updates at the intended rate. This workaround should avoid the issue on pre-API 26 devices as well, but it imposes some overhead - you might be able to avoid leaving the Java client enabled with a flow like this (haven't tested this but should work in theory):
a. Enable sensor from Java at expected rate (e.g. 200Hz)
b. Enable sensor at NDK (with default rate)
c. Set event rate in NDK to rate matching (a)
d. Disable Java request
Hopefully you'll be able to use one of these two approaches to address the issue for devices in the wild. I'll also look into fixing the root cause in Pixel 2, plus notify the chipset vendor, and see about adding new CTS tests to ensure that future/upgrading devices are not afflicted by this problem.
ne...@gmail.com <ne...@gmail.com> #14
This issue happens also to Samsung J7
bd...@google.com <bd...@google.com> #15
Marking this as fixed now, because (1) this issue is addressed in Pixel 2 with Android P, (2) the vendor has been notified of the problem and has made the fix available for propagation, and (3) a future version of Android will enforce that this bug does not exist through CTS testing.
Description
It appears that there's an issue with listening to the ASENSOR_TYPE_ROTATION_VECTOR sensor via native code. To simplify, this is done by calling ASensorManager_getDefaultSensor with 11 as the sensor id and then doing ASensorEventQueue_enableSensor.
We set the update rate for this sensor to 20000 (the value of SENSOR_DELAY_GAME). This gives us the correct results at the correct rate on most devices, but it fails to do so on a few devices such as Galaxy S6 Edge (with 7.0 OS) and Pixel 2. On these devices the updates are either too slow (10 slower than expected) or they contain duplicate data (10 events with different timestamps but the same values).
I am attaching an android studio project that should show the issue. To reproduce it, just deploy to one of the specified devices and notice that the values on the screen update rather slowly in comparison to other devices.
There's also an interesting interaction with java code - if we enable the sensor from java instead of native code first, the native and java events arrive fast - as expected. But if we enable the sensor from native code, both native and java sensors start reporting the data slowly.
The only other sensor that's affected by this issue is ASENSOR_TYPE_ROTATION_VECTOR. We do not get the same slow behaviour from any other sensor with the same setup.
Even though this problem appears to only affect certain devices, it's climbing to the top of our most voted issues, thus getting this fixed is very important to us and our users: