40

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/

Community
  • 1
  • 1
Sebastian Krysmanski
  • 8,114
  • 10
  • 49
  • 91
  • Check my answer in this questino - http://stackoverflow.com/questions/10274920/how-to-get-printf-messgaes-written-in-ndk-application/10275209#10275209 – Shaiful May 16 '12 at 04:58
  • 1
    I'm aware of this solution (and that's what I ended up using). However, the original question still remains. Maybe it's just a bug. – Sebastian Krysmanski May 22 '12 at 09:22
  • Have you tried removing the setvbuf call? I have printf follwed by fflush showing up in the log correctly in code that does not use setvbuf. – Josh Heitzman Dec 23 '12 at 02:57
  • See the comment from svdree in this answer - it appears this functionality (the stop, set prop, start approach) does not work: http://stackoverflow.com/questions/5499202/why-is-redirecting-stdout-stderr-on-android-not-working – Mick Jan 03 '13 at 17:05
  • 1
    stop / setprop / start works if you're root. None of those commands gives you an error message when they fail due to lack of permission. – fadden Jun 19 '13 at 19:53

6 Answers6

22

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

sqr163
  • 1,074
  • 13
  • 24
  • 6
    The solution linked here should be marked as the solution as it does not require rooting or any other special privileges. Just call an "init" function up front and all cout calls end up in LogCat...sweet. – gnichola Jul 12 '16 at 18:28
17

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
user2802811
  • 171
  • 1
  • 3
13

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);

9

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;
}
Shailesh
  • 328
  • 5
  • 15
Sergey Pekar
  • 8,555
  • 7
  • 47
  • 54
  • @AshrafSayied-Ahmad unfortunately there is no standard way to do it. The only way to that you can only use android logging library for writing logical on NDK. Only thing I can suggest use it instead of default C language output – Sergey Pekar May 22 '18 at 15:37
7

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.

Community
  • 1
  • 1
fadden
  • 51,356
  • 5
  • 116
  • 166
-1

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.

Mārtiņš Možeiko
  • 12,733
  • 2
  • 45
  • 45
  • Unfortunately, neither "fflush()" nor "setvbuf()" have any effect - regardless of whether I use stdout or stderr. I did test it with "fflush()" previously but I just forgot to add it to my example. I have now. – Sebastian Krysmanski May 11 '12 at 06:44