Original code that prints to stderr:
extern "C" {
/* error: output error message */
void Error(const int error, char *message, ...)
{
va_list arg;
fflush(stdout);
fflush(stderr);
if (error > 0)
fprintf(stderr, "\nError: ");
else
fprintf(stderr, "\nWarning: ");
va_start(arg, message);
vfprintf(stderr, message, arg);
va_end(arg);
fflush(stderr);
if (error > 0)
exit(error);
}
void main(){
Error(0,"Problem %s in file", "sometext");
}
}//extern "C"
I modified my code to look like that. It should print to logcat.
extern "C" {
#include <android/log.h>
#include <jni.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <math.h>
/* error: output error message */
void Error(const int error, char *message, ...)
{
va_list arg;
va_start(arg, message);
if (error > 0)
__android_log_print(ANDROID_LOG_ERROR, "HTS_API", message, arg);
else
__android_log_print(ANDROID_LOG_WARN, "HTS_API", message, arg);
va_end(arg);
if (error > 0)
exit(error);
}
void main(){
Error(0,"Problem %s in file", "sometext");
}
}//extern "C"
Problem is that my code outputs: 'Problem |�;A.|�;A. in file'
Calling the logger function directly, I will get the expected output.
__android_log_print(ANDROID_LOG_WARN, "HTS_API","Problem %s in file", "sometext");
The expected output is: 'Problem sometext in file'
What am I doing wrong?
__android_log_print does not accept a va_list as a parameter. It accepts a variable parameter list.
It looks like in the newest NDK they've added
int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap);
which is what you want. Formerly you'd have to fix this problem by either re-implementing Error as a macro with variable argument list, or using vsprintf to format the error message in a buffer and then say
__android_log_print(ANDROID_LOG_WARN, "HTS_API", "%s", buf);
Related
I don't know if I'm wrong but I found this solution to bypass Android restriction on private shared library like OpenCL. It copies required libs from /system/vendor/lib64 to /data/data/package.name/ and then loads them by calling dlopen.
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <jni.h>
#include <android/log.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <errno.h>
#include <unistd.h>
#define LOG_TAG "JNI"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
void copy_file(const char* in_path, const char* out_path) {
FILE* fin = fopen(in_path, "rb");
check(fin, "fopen()");
FILE* fout = fopen(out_path, "wb");
check(fout, "fopen()");
unsigned char buffer[255];
size_t ret;
while ((ret = fread(buffer, sizeof(*buffer), ARRAY_SIZE(buffer), fin)) == ARRAY_SIZE(buffer)) {
fwrite(buffer, sizeof(*buffer), ret, fout);
}
if (ferror(fin) != 0) {
LOGE("Error on read");
exit(1);
}
fwrite(buffer, sizeof(*buffer), ret, fout);
fclose(fin);
fclose(fout);
}
void* sdlopen(const char* path){
void *handle;
handle = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
if (!handle) {
LOGE("#1 %s", dlerror());
exit(1);
}
return handle;
}
void load(){
void *handle, *handle1, *handle2, *handle3, *handle4, *handle5, *handle6;
cl_int (*_clGetPlatformIDs)(cl_uint, cl_platform_id*, cl_uint*);
char *error;
copy_file("/system/vendor/lib64/libOpenCL.so", "/data/data/com.app.opencl/libOpenCL.so");
copy_file("/system/lib64/libcutils.so", "/data/data/com.app.opencl/libcutils.so");
copy_file("/system/lib64/libbase.so", "/data/data/com.app.opencl/libbase.so");
copy_file("/system/lib64/libc++.so", "/data/data/com.app.opencl/libc++.so");
copy_file("/system/lib64/libvndksupport.so", "/data/data/com.app.opencl/libvndksupport.so");
copy_file("/system/lib64/libdl_android.so", "/data/data/com.app.opencl/libdl_android.so");
copy_file("/system/lib64/ld-android.so", "/data/data/com.app.opencl/ld-android.so");
handle1 = sdlopen("/data/data/com.app.opencl/libc++.so");
handle2 = sdlopen("/data/data/com.app.opencl/ld-android.so");
handle3 = sdlopen("/data/data/com.app.opencl/libdl_android.so");
handle4 = sdlopen("/data/data/com.app.opencl/libvndksupport.so");
handle5 = sdlopen("/data/data/com.app.opencl/libbase.so");
handle6 = sdlopen("/data/data/com.app.opencl/libcutils.so");
handle = sdlopen("/data/data/com.app.opencl/libOpenCL.so");
_clGetPlatformIDs = dlsym(handle, "clGetPlatformIDs");
if ((error = dlerror()) != NULL) {
LOGE("#2 %s", error);
exit(1);
}
dlclose(handle);
dlclose(handle1);
dlclose(handle2);
dlclose(handle3);
dlclose(handle4);
dlclose(handle5);
dlclose(handle6);
}
With the code above I can dlopen libOpenCL.so but
dlsym(handle, "clGetPlatformIDs");
returns undefined symbol: JNI_OnLoad. I think it shouldn't look for JNI_OnLoad function. What is wrong?
I have a problem with this:
C code
#define CREATE_HTML_FILE_SCRIPT "/bin/curl https://coinmarketcap.com/it/currencies/bytecoin-bcn/ > /data/data/com.example.bytecoin/bcn.html"
#define CREATE_TEMP_FILE_SCRIPT "/data/local/lynx /data/data/com.example.bytecoin/bcn.html -dump > /data/data/com.example.bytecoin/bcn.txt"
system(CREATE_HTML_FILE_SCRIPT);
system(CREATE_TEMP_FILE_SCRIPT);
If I run from adb shell these commands all works well but when these command are executed from the app, file.html and file.txt are empty... I don't understand why and how I can solve it.
Well, lynx is an interactive program, so I think you'll run in trouble when using it from a system() call. But not with curl:
/* pru_curl-1.c */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *cmd = "curl https://www.google.com/";
system(cmd); /* you will get the output of curl on stdout */
exit(EXIT_SUCCESS);
}
This is with curl redirecting its output in the shell call with the > operator:
/* pru_curl-2.c */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *cmd = "curl https://www.google.com/ >output_file-2";
/* you will get the output of curl on output_file-2 */
system(cmd);
exit(EXIT_SUCCESS);
}
Curl, on the other side, allows you to specify -o output_file.txt and you'll be able to read the file, once the program has finished.
/* pru_curl-3.c */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *cmd = "curl https://www.google.com/ -o output_file-3";
/* you will get the output of curl on output_file-3 */
system(cmd);
exit(EXIT_SUCCESS);
}
You have a third alternative, which is using popen(3), that allows you to start the program as a subcommand, and read the output of that program from the FILE * descriptor you get from popen(3). You could use it like this (processing character by character):
/* pru_curl-4.c */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *cmd = "curl https://www.google.com/";
FILE *f = popen(cmd, "r");
if (!f) {
fprintf(stderr, "%s: %s\n",
cmd, strerror(errno));
exit(EXIT_FAILURE);
}
int c;
while((c = fgetc(f)) != EOF) {
printf("[%d]", c); /* you will get the downloaded file as
* sequences of numbers (the character
* values) embedded in square brackets on
* stdout */
}
pclose(f);
exit(EXIT_SUCCESS);
}
or (processing line by line):
/* pru_curl-5.c */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *cmd = "curl https://www.google.com/";
FILE *f = popen(cmd, "r");
if (!f) {
fprintf(stderr, "%s: %s\n",
cmd, strerror(errno));
exit(EXIT_FAILURE);
}
char line[256];
while (fgets(line, sizeof line, f)) {
/* you'll get your output in chunks of one line, or 256 bytes
* ---if longer---, encapsulated by a pair of square brackets
* drawn in a different color (gren, by the escape sequences
* used) */
fprintf(stderr,
"\033[1;33m[\033[m%s\033[32m]\033[m",
line);
}
pclose(f);
exit(EXIT_SUCCESS);
}
or (by blocks):
/* pru_curl-6.c */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 8 /* blocks in buffer */
#define CPB 11 /* chars per block */
int main()
{
char *cmd = "curl https://www.google.com/";
FILE *f = popen(cmd, "r");
if (!f) {
fprintf(stderr, "%s: %s\n",
cmd, strerror(errno));
exit(EXIT_FAILURE);
}
char block[N][CPB];
int n;
char *sep = "";
do {
/* print a blanck line between groups */
printf("%s", sep);
sep = "\n";
/* we read as many CPB byte blocks as possible to fill the
* N registers in buffer.
* Then we start again until we don't fill completely the
* buffer. */
n = fread(block, sizeof block[0], N, f);
int i;
for (i = 0; i < n; i++) {
printf("[%.*s]\n", (int)sizeof block[i], block[i]);
}
printf("finished one loop of %d blocks of %d chars, each.\n",
N, (int) sizeof block[0]);
} while (n == N);
/* n < N, so we are finished, check that probably the last register is
* not printed because it was not complete. */
pclose(f);
exit(EXIT_SUCCESS);
}
(All these examples are complete and have been tested before posting)
Edit
I have completed the code for the six programs and now all of them are executables with just building with:
$ cc pru_curl-<i>.c -o pru_curl-<i> # <i> is the program number
$ _
In each case, you can execute the program by just running:
$ pru_curl-<i>
.... <-- a lot of output (or to a file) about the contents of the root page of google.
$ _
I am trying out Parcel with native code:
#include <stdio.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <binder/IBinder.h>
#include <binder/Binder.h>
#include <binder/ProcessState.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
using namespace android;
int main()
{
int32_t i = 123, j = 456;
Parcel data;
status_t t = data.writeInt32(j);
if(t == NO_ERROR)
printf("Status: %d\n", t);
else if(t == BAD_VALUE)
printf("Bad Value\n");
int32_t jj = 0;
t = data.readInt32(&jj);
printf("t: %d\n", t);
printf("ParcelTest: %d\n", jj);
return 0;
}
To compile this code, Android's source tree is needed. Put it under external/ParcelTest. And the Android.mk is here. Run mmma external/ParcelTest to compile.
Output of the program is:
generic_x86:/ # /system/bin/ParcelTest
Status: 0
t: -61
ParcelTest: 0
The Status: 0 indicates that writing value into the Parcel works out. But reading doesn't. So Parcel is the thing that if I read data as the order I write, I would get correct result. Any idea why this code sample fails?
The correct usage is below:
#include <stdio.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <binder/IBinder.h>
#include <binder/Binder.h>
#include <binder/ProcessState.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
using namespace android;
int main()
{
int32_t i = 123, j = 456;
Parcel data;
status_t t = data.writeInt32(j);
if(t == NO_ERROR)
printf("Status: %d\n", t);
else if(t == BAD_VALUE)
printf("Bad Value\n");
int32_t jj = 0;
data.setDataPosition(0);
t = data.readInt32(&jj);
printf("t: %d\n", t);
printf("ParcelTest: %d\n", jj);
return 0;
}
The read position has to be set manually.
I'm trying to compile an application using C++11 and OpenGL ES for Android using NativeActivity. I'm using
APP_STL := gnustl_shared
and everything compiles just fine. But when running my app I get:
dlopen(libjngl-test.so): Cannot load library: soinfo_relocate(linker.cpp:976): cannot locate symbol "_ZSt11_Hash_bytesPKvjj" referenced by "libjngl-test.so"...
jngl-test ist my activity. This is how my loading code looks like:
#include <android/native_activity.h>
#include <android/log.h>
#include <dlfcn.h>
#include <errno.h>
#include <stdexcept>
void* load_lib(const std::string& l) {
auto handle = dlopen(std::string("/data/data/com.bixense.jngl_test/lib/" + l).c_str(),
RTLD_NOW | RTLD_GLOBAL);
if (!handle) {
throw std::runtime_error(std::string("dlopen(") + l + "): " + dlerror());
}
__android_log_print(ANDROID_LOG_INFO, "bootstrap", "Loaded %s", l.c_str());
return handle;
}
void ANativeActivity_onCreate(ANativeActivity* app, void* ud, size_t udsize) {
try {
load_lib("libogg.so");
load_lib("libvorbis.so");
auto main = reinterpret_cast<void (*)(ANativeActivity*, void*, size_t)>(
dlsym(load_lib("libjngl-test.so"), "ANativeActivity_onCreate")
);
if (!main) {
throw std::runtime_error("undefined symbol ANativeActivity_onCreate");
}
main(app, ud, udsize);
} catch(std::exception& e) {
__android_log_print(ANDROID_LOG_ERROR, "bootstrap", "%s", e.what());
ANativeActivity_finish(app);
}
}
Does anybody have an idea what I'm doing wrong? Where could _ZSt11_Hash_bytesPKvjj come from?
I'm using the following bootstrapping code to load my native activity (jngl-test):
#include <android/native_activity.h>
#include <android/log.h>
#include <dlfcn.h>
#include <errno.h>
#include <stdexcept>
const std::string LIB_PATH = "/data/data/com.bixense.jngl_test/lib/";
void* load_lib(const std::string& l) {
void* handle = dlopen(l.c_str(), RTLD_NOW | RTLD_GLOBAL);
if (!handle) {
throw std::runtime_error(std::string("dlopen(") + l + "): " + strerror(errno));
}
return handle;
}
void ANativeActivity_onCreate(ANativeActivity* app, void* ud, size_t udsize) {
try {
load_lib(LIB_PATH + "libogg.so");
load_lib(LIB_PATH + "libvorbis.so");
auto main = reinterpret_cast<void (*)(ANativeActivity*, void*, size_t)>(
dlsym(load_lib(LIB_PATH + "libjngl-test.so"), "ANativeActivity_onCreate")
);
if (!main) {
throw std::runtime_error("undefined symbol ANativeActivity_onCreate");
}
main(app, ud, udsize);
} catch(std::exception& e) {
__android_log_print(ANDROID_LOG_ERROR, "bootstrap", e.what());
ANativeActivity_finish(app);
}
}
I get the following error message:
dlopen(/data/data/com.bixense.jngl_test/lib/libjngl-test.so): Invalid argument
This doesn't tell me at all whats going wrong. Is there a way to get more debug output? What could "Invalid argument" mean?
I fixed it:
dlerror()
gives a far better error message.
Here's the bootstrap code if someone is interested:
#include <android/native_activity.h>
#include <android/log.h>
#include <dlfcn.h>
#include <errno.h>
#include <stdexcept>
void* load_lib(const std::string& l) {
auto handle = dlopen(std::string("/data/data/com.bixense.jngl_test/lib/" + l).c_str(),
RTLD_NOW | RTLD_GLOBAL);
if (!handle) {
throw std::runtime_error(std::string("dlopen(") + l + "): " + dlerror());
}
return handle;
}
void ANativeActivity_onCreate(ANativeActivity* app, void* ud, size_t udsize) {
try {
load_lib("libogg.so");
load_lib("libvorbis.so");
auto main = reinterpret_cast<void (*)(ANativeActivity*, void*, size_t)>(
dlsym(load_lib("libjngl-test.so"), "ANativeActivity_onCreate")
);
if (!main) {
throw std::runtime_error("undefined symbol ANativeActivity_onCreate");
}
main(app, ud, udsize);
} catch(std::exception& e) {
__android_log_print(ANDROID_LOG_ERROR, "bootstrap", e.what());
ANativeActivity_finish(app);
}
}
You could do this..
put that lib in raw directory and load it
For raw files, you should consider creating a raw folder inside res directory and then call
getResources().openRawResource(resourceName)
from your activity.
then you can use it the way you like.