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.
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.
The program runs up to the getsockname where the return is -1 and errno is 9 (EBADF, bad file descriptor). However, the code instrumented in Android app goes well.
void sysLibCSendHookHandler(CPUState* env, int isStart){
if(isStart){
int fd = env->regs[0];
int buf = env->regs[1];
int len = env->regs[2];
int flags = env->regs[3];
DECAF_printf("xxxxx send(%d, %p, %d, %d)\n", fd, buf, len, flags);
extern int errno;
struct sockaddr_un sock_addr;
socklen_t sock_addr_len;
sock_addr_len = sizeof(sock_addr);
int t = getsockname(fd, (struct sockaddr*)&sock_addr, &sock_addr_len);
DECAF_printf("fd:%d",fd);}
This code results in undefined behavior:
extern int errno;
Per 7.5 Errors <errno.h> of the C Standard (note the bolded part):
The header defines several macros, all relating to
the reporting of error conditions.
The macros are
EDOM
EILSEQ
ERANGE
which expand to integer constant expressions with type int, distinct
positive values, and which are suitable for use in #if preprocessing
directives; and
errno
which expands to a modifiable lvalue that has type int and
thread local storage duration, the value of which is set to a
positive error number by several library functions. If a macro
definition is suppressed in order to access an actual object,
or a program defines an identifier with the name errno, the
behavior is undefined.
According to the Google Android source code, errno is a macro defined as
extern int *__geterrno(void);
#define errno (*__geterrno())
That being the case, the value you see in your extern int errno is meaningless.
Device: Google Nexus 7 (2013).
logcat contains
I/DEBUG ( 176): Abort message: '### ABORTING: invalid address or address of corrupt block 0x5c6b0 passed to dlfree'.
I think there is a problem with static libgnustl. Am I right? How can I force to use ibgnustl_shared using GNU Build System? I uses android-ndk-r9b installed into $HOME/android-ndk-r9b. Firstly I made standalone toolchain
$HOME/android-ndk-r9b/build/tools/make-standalone-toolchain.sh --platform=android-9 --install-dir=$HOME/android-toolchain
I wrote simple test that contains shared library and console program that uses it. It crashes on device.
// libtest.h
#ifndef TEST_H
#define TEST_H
#include <stddef.h>
#include <string>
namespace test
{
enum { MSG_LEN_BYTES = 3, MSG_LEN_MAX = 0xFFF };
int encodeMsgLength(std::string &encoded_length, size_t length);
}
#endif
// libtest.cpp
#include "libtest.h"
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
int test::encodeMsgLength(std::string &encoded_length, size_t length)
{
encoded_length.clear();
if (length > MSG_LEN_MAX) {
return E2BIG;
}
char buf[MSG_LEN_BYTES + 1] = {0};
int cnt = snprintf(buf, sizeof(buf), "%03zX", length);
if (cnt == MSG_LEN_BYTES && static_cast<size_t>(cnt) < sizeof(buf)) {
encoded_length.assign(buf, cnt);
return 0;
}
assert(!"encodeMsgLength");
return EBADF;
}
// test.cpp
#include <iostream>
#include <stdlib.h>
#include "libtest.h"
int main(int argc, char* argv[])
{
if (argc != 2) {
std::cout << "Usage: test <number>\n";
return 1;
}
size_t len = atoi(argv[1]);
std::cout << "encodeMsgLength(" << len << ") => ";
std::string str;
int err = test::encodeMsgLength(str, len);
std::cout << str << ", error " << err << std::endl;
return 0;
}
Makefile.am
lib_LTLIBRARIES = libtest.la
libtest_la_LDFLAGS = -shared -avoid-version
libtest_la_SOURCES = libtest.cpp
bin_PROGRAMS = test
test_LDADD = libtest.la
test_SOURCES = test.cpp
Build your app using the default : ndk-build --TARGET_PLATFORM android-9
To make sure that only shared library is taken edit your Android.mk and put appropriate library like LOCAL_SHARED_LIBS := libgnustl
There are various other tools that you can use to debug your issue:
1. gdb [search for remote debugging android native app]
2. strace [ if not directly available use busybox strace ]
3. valgrind
Also in many cases the memory stack during crash are stores in /data/tombstones. Locate your errror file, pull it and show the details here of the same.
Instead of linking to libgnustl-static.a, use libgnustl-shared.so. Your observation makes sense: when both libtest.so and test are linked with the static version, then the std::string class will have two different vtables, and the program may crash on shutdown. libstlport uses internally system stl (always shared) for new/delete, and thus behaves better in your test case. This, naturally, does not protect from other clashes, which may also be lethal. That's why you should use shared version of stl if you use it in two or more dynamically linked components.
In CPLUSPLUS-SUPPORT.html
"II.3. Static runtimes:
Please keep in mind that the static library variant of a given C++ runtime SHALL ONLY BE LINKED INTO A SINGLE BINARY for optimal conditions."
I had an issue with this where malloc was crashing.
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.