I've searched for a tutorial/an answer on polling accelerometer faster with NDK but didnt find solver yet. just found an androiddevelopers documentation here.
what i need is polling acceleration about 100 samples per second (100Hz), by default my device (Samsung Galaxy SL i9003 with gingerbread 2.3.5) with default SENSOR_DELAY_FASTEST can only get about 60 samples persecond (60Hz).
Therefore i tried to access sensor via NativeActivity with NDK by generating .c files that i try to make based on sensor.h and looper.h:
#include <jni.h>
#include <string.h>
#include <android/sensor.h>
#include <android/log.h>
#include <android/looper.h>
#define TAG "accelerondk"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOOPER_ID 1
#define SAMP_PER_SEC 100 //i've changed to 120, even 10, but nothing happen
void Java_azka_web_ndk_AcceleroNDKActivity_startMonitoring(JNIEnv* env, jclass clazz) {
ASensorManager* sensorManager = ASensorManager_getInstance();
ALooper* looper = ALooper_forThread();
if(looper == NULL)
looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
ASensorRef accelerometerSensor = ASensorManager_getDefaultSensor(sensorManager,ASENSOR_TYPE_ACCELEROMETER);
LOGI("accelerometerSensor: %s, vendor: %s", ASensor_getName(accelerometerSensor), ASensor_getVendor(accelerometerSensor));
ASensorEventQueue* queue = ASensorManager_createEventQueue(sensorManager, looper, LOOPER_ID, NULL, NULL);
ASensorEventQueue_enableSensor(queue, accelerometerSensor);
ASensorEventQueue_setEventRate(queue, accelerometerSensor, (1000L/SAMP_PER_SEC)*1000);
int ident;//identifier
int events;
while (1) {
while ((ident=ALooper_pollAll(-1, NULL, &events, NULL) >= 0)) {
// If a sensor has data, process it now.
if (ident == LOOPER_ID) {
ASensorEvent event;
while (ASensorEventQueue_getEvents(queue, &event, 1) > 0) {
LOGI("aaaaaaa accelerometer X = %f y = %f z=%f ", event.acceleration.x, event.acceleration.y, event.acceleration.z);
}
}
}
}
}
so far, i've been able to access accelerometer with NativeActivity, but there is no change with number sample had taken. even when i change ASensorEventQueue_setEventRate big enough or small enough the acceleration recorded still about 60 samples per second (1 samples per 15 milisec)
is there any mistakes in my code? or something that i forget with?
thanks in advance
I also tried a few things with the sample rate of sensors. I use a Galaxy Nexus.
If I use only the Acc-Sensor the frequency is very low (about 40Hz), but if I use the Acc-Sensor plus the magnetic- and the gyro-sensor the sample rate for each sensor is about 100Hz.
I have no explanation why this happens. Another observation is that the values passed to ASensorEventQueue_setEventRate have no effect. The sample-rate is always the same.
The behaviour is exactly the same for SDK-Code.
Here is the code I used for benchmarking:
#include <string.h>
#include <jni.h>
#include <android/sensor.h>
#include <android/looper.h>
#include <android/log.h>
#include <time.h>
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "TestJNIActivity", __VA_ARGS__))
#define LOOPER_ID 1
#define SAMP_PER_SEC 100
ASensorEventQueue* sensorEventQueue;
int accCounter = 0;
int64_t lastAccTime = 0;
int gyroCounter = 0;
int64_t lastGyroTime = 0;
int magCounter = 0;
int64_t lastMagTime = 0;
/* This is a trivial JNI example where we use a native method
* to return a new VM String. See the corresponding Java source
* file located at:
*
* apps/samples/hello-jni/project/src/com/example/HelloJni/HelloJni.java
*/
static int get_sensor_events(int fd, int events, void* data);
struct tm* start;
struct tm* finish;
jstring
Java_de_tum_ndktest_TestJNIActivity_stringFromJNI( JNIEnv* env, jobject thiz )
{
LOGI("stringFromJNI");
return (*env)->NewStringUTF(env,"Hello from JNI !");
}
void
Java_de_tum_ndktest_TestJNIActivity_sensorValue( JNIEnv* env, jobject thiz ) {
ASensorEvent event;
int events, ident;
ASensorManager* sensorManager;
const ASensor* accSensor;
const ASensor* gyroSensor;
const ASensor* magSensor;
void* sensor_data = malloc(1000);
LOGI("sensorValue() - ALooper_forThread()");
ALooper* looper = ALooper_forThread();
if(looper == NULL)
{
looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
}
sensorManager = ASensorManager_getInstance();
accSensor = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_ACCELEROMETER);
gyroSensor = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_GYROSCOPE);
magSensor = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_MAGNETIC_FIELD);
sensorEventQueue = ASensorManager_createEventQueue(sensorManager, looper, 3, get_sensor_events, sensor_data);
ASensorEventQueue_enableSensor(sensorEventQueue, accSensor);
ASensorEventQueue_enableSensor(sensorEventQueue, gyroSensor);
ASensorEventQueue_enableSensor(sensorEventQueue, magSensor);
//Sampling rate: 100Hz
int a = ASensor_getMinDelay(accSensor);
int b = ASensor_getMinDelay(gyroSensor);
int c = ASensor_getMinDelay(magSensor);
LOGI("min-delay: %d, %d, %d",a,b,c);
ASensorEventQueue_setEventRate(sensorEventQueue, accSensor, 100000);
ASensorEventQueue_setEventRate(sensorEventQueue, gyroSensor, 100000);
ASensorEventQueue_setEventRate(sensorEventQueue, magSensor, 100000);
LOGI("sensorValue() - START");
}
static int get_sensor_events(int fd, int events, void* data) {
ASensorEvent event;
//ASensorEventQueue* sensorEventQueue;
while (ASensorEventQueue_getEvents(sensorEventQueue, &event, 1) > 0) {
if(event.type == ASENSOR_TYPE_ACCELEROMETER) {
//LOGI("accl(x,y,z,t): %f %f %f %lld", event.acceleration.x, event.acceleration.y, event.acceleration.z, event.timestamp);
if(accCounter == 0 || accCounter == 1000)
{
LOGI("Acc-Time: %lld (%f)", event.timestamp,((double)(event.timestamp-lastAccTime))/1000000000.0);
lastAccTime = event.timestamp;
accCounter = 0;
}
accCounter++;
}
else if(event.type == ASENSOR_TYPE_GYROSCOPE) {
//LOGI("accl(x,y,z,t): %f %f %f %lld", event.acceleration.x, event.acceleration.y, event.acceleration.z, event.timestamp);
if(gyroCounter == 0 || gyroCounter == 1000)
{
LOGI("Gyro-Time: %lld (%f)", event.timestamp,((double)(event.timestamp-lastGyroTime))/1000000000.0);
lastGyroTime = event.timestamp;
gyroCounter = 0;
}
gyroCounter++;
}
else if(event.type == ASENSOR_TYPE_MAGNETIC_FIELD) {
//LOGI("accl(x,y,z,t): %f %f %f %lld", event.acceleration.x, event.acceleration.y, event.acceleration.z, event.timestamp);
if(magCounter == 0 || magCounter == 1000)
{
LOGI("Mag-Time: %lld (%f)", event.timestamp,((double)(event.timestamp-lastMagTime))/1000000000.0);
lastMagTime = event.timestamp;
magCounter = 0;
}
magCounter++;
}
}
//should return 1 to continue receiving callbacks, or 0 to unregister
return 1;
}
Question is a bit old but maybe these two articles will help out a bit for anyone else that stumbles on this question and wonders why bother, or how to optimize the example in the NDK a bit.
These two short articles layout the issues and potential solutions (but no complete source solution)
Java interfaced sensor performance
Native Sampling Improvement
This is an old question but given the lack of documentation and articles out there, I thought I'd share my experience. I did all my tests on a Nexus 5X. Your device might be different.
The original code looks right. What isn't obvious from the documentation is that you can only set the event rate after enabling the sensor, and that...
If you re-enable the sensor (say, after onPause() and onResume()), you need to set the event rate again. If you had a "double enable" like I did in my code (enable()/setEventRate() in init(), but only enable() in onResume()), you will get the default polling rate.
You are probably limited by the speed of the accelerometer hardware in your device. However, you could use interpolation to get some extra data points.
Related
I am trying to read touchscreen event, in my device /dev/input/event4 is used for touchscreen, while in some other phone, event7 is used for touchscreen.
I am looking for a c function that can help me
to find that touchscreen event.
Each input event device has a corresponding entry in the /sys/class/input/ pseudo-file hierarchy. (See Linux Input Subsystem userspace API in the Linux kernel documentation for further details.) For example, the name of the device corresponding to event7 is in /sys/class/input/event7/device/name.
When you open the event character device (/dev/input/event7), you can use the EVIOCGBIT(type, bits) ioctl to check which kind of events the device can produce. Touchpads will produce EV_ABS events ABS_X and ABS_Y, and EV_KEY event BTN_TOUCH.
Therefore, if you glob /dev/input/event*, open each device in turn, and check if they report the abovementioned three events, you are likely to find the device you look for. For example:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <linux/input.h>
#include <fcntl.h>
#include <limits.h>
#include <string.h>
#include <glob.h>
#include <errno.h>
#include <stdio.h>
#ifndef ULONG_BITS
#define ULONG_BITS (CHAR_BIT * sizeof (unsigned long))
#endif
static inline int has_bit(const unsigned long data[], const size_t bit)
{
return !!(data[bit / ULONG_BITS] & (1uL << (bit % ULONG_BITS)));
}
char *touchscreen_event_device(size_t skip)
{
glob_t files;
int result;
result = glob("/dev/input/event*", 0, NULL, &files);
if (result) {
if (result == GLOB_NOSPACE) {
errno = ENOMEM;
return NULL;
} else
if (result == GLOB_NOMATCH) {
errno = ENOENT;
return NULL;
} else {
errno = EACCES;
return NULL;
}
}
for (size_t i = 0; i < files.gl_pathc; i++) {
int fd = open(files.gl_pathv[i], O_RDONLY);
if (fd != -1) {
unsigned long absbits[1 + ABS_MAX / ULONG_BITS] = { 0 };
unsigned long keybits[1 + KEY_MAX / ULONG_BITS] = { 0 };
if (ioctl(fd, EVIOCGBIT(EV_ABS, ABS_MAX+1), &absbits) != -1 &&
ioctl(fd, EVIOCGBIT(EV_KEY, KEY_MAX+1), &keybits) != -1) {
if (has_bit(absbits, ABS_X) &&
has_bit(absbits, ABS_Y) &&
has_bit(keybits, BTN_TOUCH)) {
/* Device reports ABS_X, ABS_Y and BTN_TOUCH,
and therefore is a touchpad device. */
if (!skip) {
char *devpath = strdup(files.gl_pathv[i]);
close(fd);
globfree(&files);
if (!devpath)
errno = ENOMEM;
return devpath;
} else {
skip--;
}
}
}
close(fd);
}
}
globfree(&files);
errno = ENOENT;
return NULL;
}
int main(void)
{
size_t i = 0;
while (1) {
char *devpath = touchscreen_event_device(i);
if (!devpath) {
if (i)
break;
fprintf(stderr, "No touchscreen input event devices found: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
printf("Found touchscreen input event device '%s'\n", devpath);
free(devpath);
i++;
}
return EXIT_SUCCESS;
}
Compile using e.g. gcc -Wall -Wextra -O2 example.c -o example, and run with root privileges, and it will list the paths to the input event devices it believes are touch screens.
An answer for a complete code could be difficult because it's a long/heavy work.
I'll point you in right directions:
read "Input Event Codes": https://www.kernel.org/doc/html/v4.14/input/event-codes.html
then you have to list all /dev/input/* files
open each of them using "fd = open("/dev/input/xxxxx", O_RDONLY);"
call "ioctl(fd, EVIOCGBIT(EV_REL, sizeof(maskbit)), maskbit)" (calling this changing "EV_REL" with others "Input Event Codes"
analize "maskbit" by searching for some specific Values that only Touchscreen has
A possibile example could find here: https://android.googlesource.com/device/generic/brillo/+/d1917142dc905d808519023d80a664c066104600/examples/keyboard/keyboard_example.cpp in which the author looking for an Input that supports "KEY_B" Event Code.
Touchscreens should have:
for EV_ABS:
ABS_X
ABS_Y
ABS_MT_SLOT
ABS_MT_POSITION_X
ABS_MT_POSITION_Y
ABS_MT_TRACKING_ID
If the Input has all these Bit it is a Touchscreen (reference: https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt)
adb shell dumpsys input - this will show the list of all event nodes with the details that you are looking for
I use superpowered, I need send midi note to a controller midi.
The problem is that I saw a function send(int deviceID, unsigned char *data, int bytes);
Where in their source code say:
deviceID: Device identifier.
data: Raw MIDI data.
bytes: Number of
bytes.
I don't know the values that I need put exactly on data and bytes to work.
The raw midi could be 0x80 - 0x48 - 0x00(start of C4 note, pitch= 72, See values)
And the bytes 1001nnnn0kkkkkkk0kkkkkkk(note on event See values) for example?
Something like that:
SuperpoweredUSBMIDI::send(deviceID, reinterpret_cast(0x80 - 0x48 - 0x00), 1001nnnn0kkkkkkk0kkkkkkk);
The problem that always crash, and I can't debug or get the error for the reason that I use the mobile with otg to replicate the error.
When I find a solution, I will put it as soon as I can.
I'm newbie with markdown, sorry for any mistakes and my English grammar.
Edit: I'm using the example project that they have on GitHub for testing purposes, specifically the simpleusb project. (source)
I make a small modifications and work, but with this specifically I try with many ways and nothing. I think this simple macrochange at least could work if I insert well the values
class simpleusb.cpp:
#include <jni.h>
#include <math.h>
#include <SuperpoweredCPU.h>
#include <AndroidIO/SuperpoweredUSBAudio.h>
#include <malloc.h>
#include <pthread.h>
// Called when the application is initialized. You can initialize SuperpoweredUSBSystem
// at any time btw. Although this function is marked __unused, it's due Android Studio's
// annoying warning only. It's definitely used.
__unused jint JNI_OnLoad (
JavaVM * __unused vm,
void * __unused reserved
) {
SuperpoweredUSBSystem::initialize(NULL, NULL, NULL, NULL, NULL);
return JNI_VERSION_1_6;
}
// Called when the application is closed. You can destroy SuperpoweredUSBSystem at any time btw.
// Although this function is marked __unused, it's due Android Studio's annoying warning only.
// It's definitely used.
__unused void JNI_OnUnload (
JavaVM * __unused vm,
void * __unused reserved
) {
SuperpoweredUSBSystem::destroy();
}
// A helper structure for sine wave output.
typedef struct sineWaveOutput {
float mul;
unsigned int step;
} sineWaveOutput;
// This is called periodically for audio I/O. Audio is always 32-bit floating point,
// regardless of the bit depth preference. (SuperpoweredUSBAudioProcessingCallback)
static bool audioProcessing (
void *clientdata,
int __unused deviceID,
float *audioIO,
int numberOfSamples,
int samplerate,
int __unused numInputChannels,
int numOutputChannels
) {
// If audioIO is NULL, then it's the very last call, IO is closing.
if (!audioIO) {
// Free memory for sine wave struct.
free(clientdata);
return true;
}
sineWaveOutput *swo = (sineWaveOutput *)clientdata;
if (swo->mul == 0.0f) swo->mul = (2.0f * float(M_PI) * 300.0f) / float(samplerate);
// Output sine wave on all output channels.
for (int n = 0; n < numberOfSamples; n++) {
float v = sinf(swo->step++ * swo->mul) * 0.5f;
for (int c = 0; c < numOutputChannels; c++) *audioIO++ = v;
}
return true; // Return false for silence, true if we put audio output into audioIO.
}
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static int latestMidiCommand = -1;
static int latestMidiChannel = 0;
static int latestMidiNumber = 0;
static int latestMidiValue = 0;
// This is called when some MIDI data is coming in.
// We are doing some primitive MIDI data processing here.
static void onMidiReceived (
void * __unused clientdata,
int __unused deviceID,
unsigned char *data,
int bytes
) {
while (bytes > 0) {
if (*data > 127) {
int command = *data >> 4;
switch (command) {
case 8: // note off
case 9: // note on
case 11: // control change
pthread_mutex_lock(&mutex);
// store incoming MIDI data
latestMidiCommand = command;
latestMidiChannel = *data++ & 15;
latestMidiNumber = *data++;
latestMidiValue = *data++;
pthread_mutex_unlock(&mutex);
bytes -= 3;
break;
default:
data++;
bytes--;
}
} else {
data++;
bytes--;
}
}
}
// Beautifying the ugly Java-C++ bridge (JNI) with these macros.
#define PID com_superpowered_simpleusb_SuperpoweredUSBAudio // Java package name and class name. Don't forget to update when you copy this code.
#define MAKE_JNI_FUNCTION(r, n, p) extern "C" JNIEXPORT r JNICALL Java_ ## p ## _ ## n
#define JNI(r, n, p) MAKE_JNI_FUNCTION(r, n, p)
// This is called by the SuperpoweredUSBAudio Java object when a USB device is connected.
JNI(jint, onConnect, PID) (
JNIEnv *env,
jobject __unused obj,
jint deviceID,
jint fd,
jbyteArray rawDescriptor
) {
jbyte *rd = env->GetByteArrayElements(rawDescriptor, NULL);
int dataBytes = env->GetArrayLength(rawDescriptor);
int r = SuperpoweredUSBSystem::onConnect(deviceID, fd, (unsigned char *)rd, dataBytes);
env->ReleaseByteArrayElements(rawDescriptor, rd, JNI_ABORT);
// r is 0 if SuperpoweredUSBSystem can't do anything with the connected device.
// r & 2 is true if the device has MIDI. Start receiving events.
if (r & 2) {
SuperpoweredUSBMIDI::startIO(deviceID, NULL, onMidiReceived);
//TODO HERE IT'S THE PROBLEM: error: integer literal is too large to be represented in any integer type
SuperpoweredUSBMIDI::send(deviceID, reinterpret_cast<unsigned char *>(0x80 - 0x48 - 0x00), 100100010011100000000011);
//FINISH PROBLEM
}
// r & 1 is true if the device has audio. Start output.
if (r & 1) {
// allocate struct for sine wave oscillator
sineWaveOutput *swo = (sineWaveOutput *)malloc(sizeof(sineWaveOutput));
if (swo) {
swo->mul = 0.0f;
swo->step = 0;
SuperpoweredCPU::setSustainedPerformanceMode(true);
// Our preferred settings: 44100 Hz, 16 bits, 0 input channels, 256 output channels,
// low latency. Superpowered will set up the audio device as close as it can to these.
SuperpoweredUSBAudio::easyIO (
deviceID, // deviceID
44100, // sampling rate
16, // bits per sample
0, // numInputChannels
256, // numOutputChannels
SuperpoweredUSBLatency_Low, // latency
swo, // clientData
audioProcessing // SuperpoweredUSBAudioProcessingCallback
);
}
}
return r;
}
// This is called by the SuperpoweredUSBAudio Java object when a USB device is disconnected.
JNI(void, onDisconnect, PID) (
JNIEnv * __unused env,
jobject __unused obj,
jint deviceID
) {
SuperpoweredUSBSystem::onDisconnect(deviceID);
SuperpoweredCPU::setSustainedPerformanceMode(false);
}
#undef PID
#define PID com_superpowered_simpleusb_MainActivity
// This is called by the MainActivity Java object periodically.
JNI(jintArray, getLatestMidiMessage, PID) (
JNIEnv *env,
jobject __unused obj
) {
jintArray ints = env->NewIntArray(4);
jint *i = env->GetIntArrayElements(ints, 0);
pthread_mutex_lock(&mutex);
i[0] = latestMidiCommand;
i[1] = latestMidiChannel;
i[2] = latestMidiNumber;
i[3] = latestMidiValue;
pthread_mutex_unlock(&mutex);
env->ReleaseIntArrayElements(ints, i, 0);
return ints;
}
The other important class but I don't change on this problem, MainActivity:
#RequiresApi(api = Build.VERSION_CODES.M)
public class MainActivity extends AppCompatActivity implements SuperpoweredUSBAudioHandler {
private Handler handler;
private TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.text);
SuperpoweredUSBAudio usbAudio = new SuperpoweredUSBAudio(getApplicationContext(), this);
usbAudio.check();
// Update UI every 40 ms.
Runnable runnable = new Runnable() {
#Override
public void run() {
int[] midi = getLatestMidiMessage();
switch (midi[0]) {
case 8: textView.setText(String.format(Locale.ENGLISH, "Note Off, CH %d, %d, %d",
midi[1] + 1, midi[2], midi[3]));
break;
case 9: textView.setText(String.format(Locale.ENGLISH, "Note On, CH %d, %d, %d",
midi[1] + 1, midi[2], midi[3]));
break;
case 11: textView.setText(String.format(Locale.ENGLISH, "Control Change, CH %d, %d, %d",
midi[1] + 1, midi[2], midi[3]));
break;
}
handler.postDelayed(this, 40);
}
};
handler = new Handler();
handler.postDelayed(runnable, 40);
/*Not look, only for testing purposes and for remember what use.
byte[] buffer = new byte[32];
int numBytes = 0;
int channel = 6; // MIDI channels 1-16 are encoded as 0-15.
buffer[numBytes++] = (byte)(0x90 + (channel - 1)); // note on
buffer[numBytes++] = (byte)60; // pitch is middle C
buffer[numBytes++] = (byte)127; // max velocity
int offset = 0;*/
}
public void onUSBAudioDeviceAttached(int deviceIdentifier) {
}
public void onUSBMIDIDeviceAttached(int deviceIdentifier) {
}
public void onUSBDeviceDetached(int deviceIdentifier) {
}
// Function implemented in the native library.
private native int[] getLatestMidiMessage();
static {
System.loadLibrary("SuperpoweredExample");
}
}
Error that I can't build app finally:
Build command failed.
Error while executing process D:\Users\ramoc\AppData\Local\Android\sdk\cmake\3.6.4111459\bin\cmake.exe with arguments {--build F:\PROYECTOFIN\SuperpoweredUSBExample\simpleusb\.externalNativeBuild\cmake\debug\arm64-v8a --target SuperpoweredExample}
[1/2] Building CXX object CMakeFiles/SuperpoweredExample.dir/simpleusb.cpp.o
FAILED: D:\Users\ramoc\AppData\Local\Android\sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe --target=aarch64-none-linux-android --gcc-toolchain=D:/Users/ramoc/AppData/Local/Android/sdk/ndk-bundle/toolchains/aarch64-linux-android-4.9/prebuilt/windows-x86_64 --sysroot=D:/Users/ramoc/AppData/Local/Android/sdk/ndk-bundle/sysroot -DSuperpoweredExample_EXPORTS -IF:/PROYECTOFIN/SuperpoweredUSBExample/simpleusb/src/main/jni/src/main/jni -IF:/PROYECTOFIN/SuperpoweredUSBExample/simpleusb/../../../Superpowered -isystem D:/Users/ramoc/AppData/Local/Android/sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/include -isystem D:/Users/ramoc/AppData/Local/Android/sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/libs/arm64-v8a/include -isystem D:/Users/ramoc/AppData/Local/Android/sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/include/backward -isystem D:/Users/ramoc/AppData/Local/Android/sdk/ndk-bundle/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=21 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa,--noexecstack -Wformat -Werror=format-security -fsigned-char -IF:\PROYECTOFIN\SuperpoweredUSBExample\simpleusb\..\..\..\Superpowered -O0 -fno-limit-debug-info -fPIC -MD -MT CMakeFiles/SuperpoweredExample.dir/simpleusb.cpp.o -MF CMakeFiles\SuperpoweredExample.dir\simpleusb.cpp.o.d -o CMakeFiles/SuperpoweredExample.dir/simpleusb.cpp.o -c F:\PROYECTOFIN\SuperpoweredUSBExample\simpleusb\src\main\jni\simpleusb.cpp
F:\PROYECTOFIN\SuperpoweredUSBExample\simpleusb\src\main\jni\simpleusb.cpp:129:100: error: integer literal is too large to be represented in any integer type
SuperpoweredUSBMIDI::send(deviceID, reinterpret_cast<unsigned char *>(0x80 - 0x48 - 0x00), 100100010011100000000011);
^
F:\PROYECTOFIN\SuperpoweredUSBExample\simpleusb\src\main\jni\simpleusb.cpp:129:100: warning: implicit conversion from 'unsigned long long' to 'int' changes value from 7976667151972931595 to 887068683 [-Wconstant-conversion]
SuperpoweredUSBMIDI::send(deviceID, reinterpret_cast<unsigned char *>(0x80 - 0x48 - 0x00), 100100010011100000000011);
~~~~~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~
1 warning and 1 error generated.
ninja: build stopped: subcommand failed.
Maybe it's for the documentation, very newbie with jni or too complex to me for now to understand 100%.
Ok, so here's what send is saying:
send(int deviceID, unsigned char *data, int bytes);
Send to deviceId a pointer to a buffer called data that has a certain number of bytes.
So when you say:
SuperpoweredUSBMIDI::send(deviceID, reinterpret_cast(0x80 - 0x48 - 0x00), 100100010011100000000011);
What you are essentially saying is "subtract these 3 numbers: 0x80 - 0x48 - 0x00", then re-interpret that number as a pointer to a buffer somewhere in memory. That buffer in memory contains 100100010011100000000011 bytes of data that I want you to read.
To fix this, we would send the data like this:
unsigned char* send_buffer[32] = {0}; // zero out buffer to use as scratch
send_buffer[0] = 0x90;
send_buffer[1] = 0x48;
send_buffer[2] = 0x00;
SuperpoweredUSBMIDI::send(deviceID, send_buffer, 3);
i thought midi had a check sum value (byte) appended to the sequence - is that done in your code or in the library code?
the message should be an array of unsigned char and pass the address of the array (name)
well that's what id have done in C when I was programming midi.
I'm trying to make a c program which triggers CVE-2017-10661.
As far as I understand because might_cancel mechanism it isn't properly protected if you make parallel operations on the file descriptor you can cause a crash.
I believe these parallel operations are read, poll etc right?
Currently i have written this piece of code.
#include <sys/timerfd.h>
#include <sys/poll.h>
#include <sys/epoll.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
int main(int ac, char *av[])
{
int timerfd;
int epollfd;
struct itimerspec timerValue;
uint64_t exp;
ssize_t s;
/* set timerfd */
timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
if (timerfd < 0) {
printf("failed to create timer fd\n");
exit(1);
}
bzero(&timerValue, sizeof(timerValue));
timerValue.it_value.tv_sec = 1;
timerValue.it_value.tv_nsec = 0;
timerValue.it_interval.tv_sec = 1;
timerValue.it_interval.tv_nsec = 0;
/* start timer */
if (timerfd_settime(timerfd, 0, &timerValue, NULL) < 0) {
printf("could not start timer\n");
exit(1);
}
s = read( timerfd, &exp, sizeof(uint64_t));
exit(0);
}
As you can see i set up a timer and then i only do a reading operation. Is there any way t trigger the bug by doing mupltiple read or pollings?
The race condition is triggered by timerfd_settime() -> timerfd_setup_cancel() -> timerfd_setup_cancel(). So you should use multiple threads to do timerfd_settime with the flag as TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET.
Here is the POC I found online.
I want my Android application to create a fake virtual device, to achieve this the device needs to be rooted and uinput module is needed.
I am using the following code to create the device, calling
static{ System.loadLibrary("myModule"); }
CreateVirtualDevice("Devname",0x123,0x123);
inside my java code.
Here the native code:
#include <string.h>
#include <jni.h>
#include <fcntl.h>
#include <linux/input.h>
#include <linux/uinput.h>
static int fd;
static struct uinput_user_dev dev;
short int analog_axis_list[] = { ABS_X,ABS_Y,ABS_RX,ABS_RY, -1};
jint Java_com_example_app_MyClass_CreateVirtualDevice(
JNIEnv* env, jobject thiz, jstring param, jint param2, jint param3) {
int i;
memset(&dev, 0, sizeof(dev));
fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if (fd < 0)
return -1;
if(ioctl(fd, UI_SET_EVBIT, EV_ABS)<0) return -4;
for(i=0;analog_axis_list[i]>=0;i++){
if(ioctl(fd,UI_SET_ABSBIT,analog_axis_list[i])<0) return -5;
dev.absmax[analog_axis_list[i]]=32767;
dev.absmin[analog_axis_list[i]]=-32768;
}
const char *cparam = (*env)->GetStringUTFChars(env, param, 0);
snprintf(dev.name, UINPUT_MAX_NAME_SIZE, cparam);
(*env)->ReleaseStringUTFChars(env, param, cparam);
dev.id.bustype = BUS_VIRTUAL;
dev.id.vendor = param2;
dev.id.product = param3;
dev.id.version = 1;
if (write(fd, &dev, sizeof(dev)) < 0)
return -7;
if (ioctl(fd, UI_DEV_CREATE) < 0)
return -8;
return 0;
}
The device is successfully created, and the return value is 0.
Inside input.h the ABSÂ values are so defined:
#define ABS_X 0x00
#define ABS_Y 0x01
#define ABS_RX 0x03
#define ABS_RY 0x04
But when checking the axis on android, I get proper values for AXIS_X and AXIS_Y, but ABS_RX and ABS_RY have wrong values. I used this code to check the axis values:
InputDevice device = InputDevice.getDevice(ids[position]);
List<InputDevice.MotionRange> ranges = device.getMotionRanges();
StringBuilder sb = new StringBuilder("");
if(ranges.size()==0){
sb.append("NO_MOTION_RANGES");
}
else{
int i = 0;
for(InputDevice.MotionRange range:ranges) {
if(i>0) {
sb.append(",");
}
sb.append(MotionEvent.axisToString(range.getAxis()));
sb.append("(").append(range.getAxis()).append(")");
i++;
}
}
return sb.toString();
And the result is:
AXIS_X(0),AXIS_Y(1),AXIS_Z(11),AXIS_RZ(14)
I am using the latest NDK release (r10d) without any particular settings enabled. What can cause these errors?
I want to point out that it's my code to have something wrong, because with an actual controller the axis numbers are correct.
Edit 1:
I tried to return analog_axis_list[2], which is ABS_RX, at the end of my function instead of 0 and it returns 3, so I think I'm passing a wrong type to the ioctl call.
Which type should I choose?
Android uses AXIS_Z and AXIS_RZ for the right stick; this is consistent with USB HID.
I have strange problems with thread affinity. I have created a program in C:
#define _GNU_SOURCE
#include<stdio.h>
#include <sys/syscall.h>
#include<string.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
#include <time.h>
#include <errno.h>
#define handle_error_en(en, msg) \
do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
#define NANOS 1000000000LL
#define SIZE 1000
void* mesaureTime(void *cpu)
{
unsigned long i = 0;
int s;
cpu_set_t cpuset;
struct timespec start, end;
long elapsed;
pthread_t id = pthread_self();
CPU_ZERO(&cpuset);
CPU_SET(*(int *) cpu, &cpuset);
s = pthread_setaffinity_np(id, sizeof(cpu_set_t), &cpuset);
if (s != 0)
handle_error_en(s, "pthread_setaffinity_np");
if(pthread_equal(id,tid[0]))
printf("Realizando test...\n");
while(i<SIZE){
clock_gettime(CLOCK_MONOTONIC, &start);
// Do some calculation.
factorial(150000);
clock_gettime(CLOCK_MONOTONIC, &end);
arrayTimes[i] = elapsed;
elapsed = end.tv_nsec - start.tv_nsec + (end.tv_sec - start.tv_sec)*NANOS;
i++;
}
printf("Finished\n");
return 0;
}
int factorial(int a){
if (a==1){
return 1;
}else{
a=a*factorial(a-1);
}
return a;
}
int main(int argc, char *argv[])
{
int i = 0;
int err, result;
int *cpu_pointer;
int cpu = atoi(argv[1]);
cpu_pointer = &cpu;
err = pthread_create(&tid[i], NULL, mesaureTime, (void *) cpu_pointer);
if (err != 0)
printf("can't create thread :[%s]", strerror(err));
else
printf("Hilo de test creado satisfactoriamente\n");
pthread_join(tid[0], NULL);
printf("\n Finalizado el test\n");
return 0;
}
This code works well in a Dual Core Intel CPU with Ubuntu, but when I have compiled it with arm-linux-gnueabi-gcc and I have executed in my Android devices (Nexus 4, Nexus 5 and S4), the program can't assign the thread in CPU 2, CPU 3 or CPU 4, it has only worked in CPU 1. The pthread_setaffinity_np function always returns an error (invalid argument) with CPU 2, 3 or 4.
I have read some questions here Is it possible to set affinity with sched_setaffinity in Android? and Android set thread affinity. I have tried it but I have obtain the same result.
The following description from the manual about this error:
EINVAL (pthread_setaffinity_np()) cpuset specified a CPU that was
outside the set supported by the kernel. (The kernel
configuration option CONFIG_NR_CPUS defines the range of the
set supported by the kernel data type used to represent CPU
sets.)
So it looks like your current kernel has been configured/built with CONFIG_NR_CPUS = 1. This seems to be reason your program is not able to set affinity to your threads to run on other core of your machine.
You may have recompile your kernel to achieve this.