Redirect stdout to logcat in Android NDK - android

I can't get my Nexus S (running Android 4.0) to redirect native stdout message to logcat. I've read that I need to do this:
$ adb shell stop
$ adb shell setprop log.redirect-stdio true
$ adb shell start
However, this doesn't seem to work. (It does break JUnit though, as mentioned here, so it's not without effect.)
For reference, here's my code:
package com.mayastudios;
import android.util.Log;
public class JniTester {
public static void test() {
Log.e("---------", "Start of test");
System.err.println("This message comes from Java.");
void printCMessage();
Log.e("---------", "End of test");
}
private static native int printCMessage();
static {
System.loadLibrary("jni_test");
}
}
And the JNI .c file:
JNIEXPORT void JNICALL
Java_com_mayastudios_JniTester_printCMessage(JNIEnv *env, jclass cls) {
setvbuf(stdout, NULL, _IONBF, 0);
printf("This message comes from C (JNI).\n");
fflush(stdout);
//setvbuf(stderr, NULL, _IONBF, 0);
//fprintf(stderr, "This message comes from C (JNI).\n");
//fflush(stderr);
}
And the Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := jni_test
LOCAL_SRC_FILES := test_jni.c
include $(BUILD_SHARED_LIBRARY)
I'm compiling this just by calling ndk-build. The native method is called correctly but I don't get any log output from it (even on verbose). I do get the log output from Java though ("This message comes from Java.").
Any hints of what I might be doing wrong?
PS: I've set up a small Mercurial repository that demonstrates the problem: https://bitbucket.org/skrysmanski/android-ndk-log-output/

setprop log.redirect-stdio true redirects only output generated by java code, but not the native code. This fact is described on developer.android.com in following way:
By default, the Android system sends stdout and stderr (System.out and System.err) output to /dev/null. In processes that run the Dalvik VM, you can have the system write a copy of the output to the log file.
To get output from the native code, I really liked this solution

This was not obvious to me from the previous answers. Even on rooted devices you need to run:
adb root
adb shell stop
adb shell setprop log.redirect-stdio true
adb shell start

You should also be able to wrap your logging code to detect if it's Android and if so use Android's logging. This may or may not be practical for everyone.
Include the logging header file:
#include <android/log.h>
Use the built in logging functionality:
__android_log_print(ANDROID_LOG_INFO, "foo", "Error: %s", foobar);

Here the code I use to to output stdout and stderr to android log
#include <android/log.h>
#include <pthread.h>
#include <unistd.h>
static int pfd[2];
static pthread_t loggingThread;
static const char *LOG_TAG = "YOU APP LOG TAG";
static void *loggingFunction(void*) {
ssize_t readSize;
char buf[128];
while((readSize = read(pfd[0], buf, sizeof buf - 1)) > 0) {
if(buf[readSize - 1] == '\n') {
--readSize;
}
buf[readSize] = 0; // add null-terminator
__android_log_write(ANDROID_LOG_DEBUG, LOG_TAG, buf); // Set any log level you want
}
return 0;
}
static int runLoggingThread() { // run this function to redirect your output to android log
setvbuf(stdout, 0, _IOLBF, 0); // make stdout line-buffered
setvbuf(stderr, 0, _IONBF, 0); // make stderr unbuffered
/* create the pipe and redirect stdout and stderr */
pipe(pfd);
dup2(pfd[1], 1);
dup2(pfd[1], 2);
/* spawn the logging thread */
if(pthread_create(&loggingThread, 0, loggingFunction, 0) == -1) {
return -1;
}
pthread_detach(loggingThread);
return 0;
}

stdout/stderr are redirected to /dev/null in Android apps. The setprop workaround is a hack for rooted devices that copies stdout/stderr to the log. See Android Native Code Debugging.

Try putting fflush(stdout); after your printf. Or alternatively use fprintf(stderr, "This message comes from C (JNI).\n");
stdout by default is buffering. stderr - is not. And you are using System.err, not System.out from Java.
Also you can disable stdout buffering with this: setvbuf(stdout, NULL, _IONBF, 0); Just make sure you call it before first printf call.

Related

How to compile and run a simple C code for Android?

Here is the basic C source code :
#include <stdio.h>
int main(void) {
puts("hello world!");
return 0;
}
I am able to compile for Android with NDK toolchain with :
aarch64-linux-android21-clang test.c
It generates an a.out file that I transfer to the Android device with :
adb push a.out /data/local/tmp
adb shell chmod 777 /data/local/tmp/a.out
When I try to run it with:
adb shell /data/local/tmp/a.out
I have the message : "/system/bin/sh: /data/local/tmp/a.out: No such file or directory"
What am I doing wrong?
you can use this nodejs script to automate build and test your c/c++ program for android
let cpp=`
#include<iostream>
#include<string>
using namespace std;
int main(){
cout<<"hellow word"<<endl;
return 0;
}
`
let args=['--target=armv7a-linux-androideabi23']
let cpu="armeabi-v7a"
wfs('test.cpp',cpp)
args.push("test.cpp")
args.push("-static-libstdc++")
//in case you want to build sharedlib uncomment next line
//args.push("-shared")
lg=run(runners.clang,args)
lg=run(runners.adb,'push a.out /data/local/tmp/a.out')
//in case -static-libstdc++ not used uncomment next line;
//copy c++_shared to same dir where to a.out
//run(adb,'push c++_shared.so /data/local/tmp/c++_shared.so')
let shellcmd=[];
shellcmd.push("cd /data/local/tmp")
//in case -static-libstdc++ not used uncomment next line;
// shellcmd.push("export LD_LIBRARY_PATH=.")
shellcmd.push("chmod +x a.out")
shellcmd.push("./a.out")
// a.out excution result
let output=run(runners.adb,`shell "${shellcmd.join("&&")}"`)
lg(output)
//++++++++++utilis++++++++++
function lg(...args){
console.log(...args)
}
function run(cmd,args){
if(args) cmd= cmd+" "+args.join(" ");
return require('child_process').execSync(cmd);
}
function wfs(p,data){
require("fs").writeFileSync(p,data)
}
In my case, I had to use "armv7a-linux-androideabiXX-clang" for compilation and then it is ok. XX must be replaced by the API version.
On my windows system, clang binaries and scripts are in the folder "D:\AndroidSdk\ndk\21.1.6352462\toolchains\llvm\prebuilt\windows-x86_64\bin"
The most recent script that can be used is "armv7a-linux-androideabi29-clang++.cmd" and it is ok for compiling C sourcecodes for running on Samsung A3 phones in my case.
I think this is because this is not a 64-bit kernel and I figured that out after Eugene Sh asked me in comments to this question (if he adds an answer then I'll accept it).

C++ code on Android - execl() function call failure

The Story - I got a script file on a rooted Android Wear device and I want to run it with my c++ code.
First I tried this int ret = system(/system/bin/sh /full/path/a.sh), it turned out that every time system() return with code 127 - command not exists error.
I found this workaround here: system is returning error 127 when called from c++ in linux and I do as #Nikhilendra said:
int ret = execl("/system/bin/sh","/system/bin/sh","/full/path/a.sh",(char*)NULL)
Now my c++ code crash at this line every time, even without return value, so I cant get any error code on this.
Any help is highly appreciated.
EDIT1:
The script a.sh itself runs correctly.
EDIT2:
My question can be understood as a follow-up of system is returning error 127 when called from c++ in linux
If you want to use one of the exec functions to mimic the system call, you have to fork a new child process first because the current process (image) is replaced by the one given in the exec call. That is, the exec will only return, if it failed.
I can't say, if the fork system call works on Android. But, you can check the exec call with this little example. I actually tested it on a Linux machine. EDIT: You may have to change the path of sh to /system/bin/sh.
The content of a.sh:
#!/bin/sh
echo "Hello World."
The content of the C++ test program (called it exec_test).
extern "C" {
#include <unistd.h>
#include <errno.h>
}
#include <iostream>
int main()
{
execl("/bin/sh","sh","./a.sh",NULL);
// execl only returns if it failed
std::cout << "errno: " << errno << std::endl;
return 0;
}
The output:
$ ./exec_test
Hello World.

where is Android NDK printf output?

I have following code c++ code:
static void print_string(JNIEnv * env, jclass clazz, jstring str){
jboolean isCopy;
const char* utf_string;
utf_string = env->GetStringUTFChars(str, &isCopy);
env->ReleaseStringUTFChars(str, utf_string);
//LOGI("%s",utf_string);
// LOGE("JNI Out = %s", utf_string);
printf("jni out: %s",utf_string);
__android_log_print(ANDROID_LOG_INFO, "MyTag", "The value is %s", utf_string);
env->ReleaseStringUTFChars(str, utf_string);
}
I don't see any output in logcat. So where does it goes? How can I see it?
Accordint to the docs the output is lost:
By default, the Android system sends stdout and stderr (System.out and System.err) output to /dev/null.
There are methods to change that (on rooted devices), for example using setprop, taken from the docs:
$ adb shell stop
$ adb shell setprop log.redirect-stdio true
$ adb shell start

Run Shell Script file On Android Embedded Device using System function in Android NDK

All
Here i want to run .sh file via system call in android NDK.
I able to run cp,rm command via system call. but sh command is not working via system call.
I also installed busy-box on android.I am using below code.I set all permission on test.sh.
Code :
#include <stdlib.h>
#include <stdio.h>
#include <android/log.h>
#include <jni.h>
#define LOG_TAG "Demo"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
void Java_com_ndkdemo_NDKdemoActivity_systemcall(JNIEnv * env, jobject obj) {
int result;
result = system("cp /mnt/sdcard/test /Download");
LOGD("result is cp %d", result);
result = system("sh ./test.sh");
LOGD("result of test.sh is %d", result);
}
Output :
result is cp 0.
result of test.sh is 0.
Here i am getting 0 in system("sh ./test.sh"); but not started the test.sh script.
cant get output "Hi" on console.
test.sh contains
#!/system/bin/
echo "Hi"
If i am executing direct command on prompt than its working fine and its given output "Hi" on console.
Please Help me to figure out this issue.
Thanks
Where are you expecting to see the "echo"? By default, android sends stdout to /dev/null.
According to the documentation you can redirect stdout and stderr to the log (so it will show up in logcat) using the following commands:
$ adb shell stop
$ adb shell setprop log.redirect-stdio true
$ adb shell start
Now you may see your echo in adb logcat.
You might want to try sh -c /full/path/to/test.sh

Android JNI debugging takes forever

I am using Eclipse + gdbserver + ndk7. It seems that debugging through native code (called by Java ) takes ages to step through (~20sec each step), What might cause that? is this normal behaviour?
You can use logging for debugging. please look at this link.
Include log.h file into your Android NDK source file
#include <android/log.h>
Add the line below to your Android.mk make file.
LOCAL_LDLIBS := -llog
Now you can start logging, this two steps allows you to write logs in Eclipse from Android NDK. Write the line below in your Android NDK code and the log will bw appear in the Eclipse
__android_log_write(ANDROID_LOG_ERROR,"Tag","Message");
use following Flags to write logs in the column which you want.
typedef enum android_LogPriority {
ANDROID_LOG_UNKNOWN = 0,
ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
ANDROID_LOG_VERBOSE,
ANDROID_LOG_DEBUG,
ANDROID_LOG_INFO,
ANDROID_LOG_WARN,
ANDROID_LOG_ERROR,
ANDROID_LOG_FATAL,
ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
} android_LogPriority
For example if you want to write in Info column you must write
__android_log_write(ANDROID_LOG_INFO,"Tag","Message");

Categories

Resources