[Android Software/Hacking General [Developers Only]] llrraa2010:
runtime library for the Logger driver

1. log interface for Java

................................................

public final class Log {

................................................

/**

* Priority constant for the println method; use Log.v.

*/

public static final int VERBOSE = 2;

/**

* Priority constant for the println method; use Log.d.

*/

public static final int DEBUG = 3;

/**

* Priority constant for the println method; use Log.i.

*/

public static final int INFO = 4;

/**

* Priority constant for the println method; use Log.w.

*/

public static final int WARN = 5;

/**

* Priority constant for the println method; use Log.e.

*/

public static final int ERROR = 6;

/**

* Priority constant for the println method.

*/

public static final int ASSERT = 7;

.....................................................

public static int v(String tag, String msg) {

return println_native(LOG_ID_MAIN, VERBOSE, tag, msg);

}

public static int v(String tag, String msg, Throwable tr) {

return println_native(LOG_ID_MAIN, VERBOSE, tag, msg + '\n' + getStackTraceString(tr));

}

public static int d(String tag, String msg) {

return println_native(LOG_ID_MAIN, DEBUG, tag, msg);

}

public static int d(String tag, String msg, Throwable tr) {

return println_native(LOG_ID_MAIN, DEBUG, tag, msg + '\n' + getStackTraceString(tr));

}

public static int i(String tag, String msg) {

return println_native(LOG_ID_MAIN, INFO, tag, msg);

}

public static int i(String tag, String msg, Throwable tr) {

return println_native(LOG_ID_MAIN, INFO, tag, msg + '\n' + getStackTraceString(tr));

}

public static int w(String tag, String msg) {

return println_native(LOG_ID_MAIN, WARN, tag, msg);

}

public static int w(String tag, String msg, Throwable tr) {

return println_native(LOG_ID_MAIN, WARN, tag, msg + '\n' + getStackTraceString(tr));

}

public static int w(String tag, Throwable tr) {

return println_native(LOG_ID_MAIN, WARN, tag, getStackTraceString(tr));

}

public static int e(String tag, String msg) {

return println_native(LOG_ID_MAIN, ERROR, tag, msg);

}

public static int e(String tag, String msg, Throwable tr) {

return println_native(LOG_ID_MAIN, ERROR, tag, msg + '\n' + getStackTraceString(tr));

}

..................................................................

/** [MENTION=278736]hide[/MENTION] */ public static native int LOG_ID_MAIN = 0;

/** [MENTION=278736]hide[/MENTION] */ public static native int LOG_ID_RADIO = 1;

/** [MENTION=278736]hide[/MENTION] */ public static native int LOG_ID_EVENTS = 2;

/** [MENTION=278736]hide[/MENTION] */ public static native int LOG_ID_SYSTEM = 3;

/** [MENTION=278736]hide[/MENTION] */ public static native int println_native(int bufID,

int priority, String tag, String msg);

}

2. JNI for logger

frameworks/base/core/jni/android_util_Log.cpp

/* //device/libs/android_runtime/android_util_Log.cpp

**

** Copyright 2006, The Android Open Source Project

**

** Licensed under the Apache License, Version 2.0 (the "License");

** you may not use this file except in compliance with the License.

** You may obtain a copy of the License at

**

** http://www.apache.org/licenses/LICENSE-2.0

**

** Unless required by applicable law or agreed to in writing, software

** distributed under the License is distributed on an "AS IS" BASIS,

** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

** See the License for the specific language governing permissions and

** limitations under the License.

*/

#define LOG_NAMESPACE "log.tag."

#define LOG_TAG "Log_println"

#include <assert.h>

#include <cutils/properties.h>

#include <utils/Log.h>

#include <utils/String8.h>

#include "jni.h"

#include "utils/misc.h"

#include "android_runtime/AndroidRuntime.h"

#define MIN(a,b) ((a<b)?a:b)

namespace android {

struct levels_t {

jint verbose;

jint debug;

jint info;

jint warn;

jint error;

jint assert;

};

static levels_t levels;

static int toLevel(const char* value)

{

switch (value[0]) {

case 'V': return levels.verbose;

case 'D': return levels.debug;

case 'I': return levels.info;

case 'W': return levels.warn;

case 'E': return levels.error;

case 'A': return levels.assert;

case 'S': return -1; // SUPPRESS

}

return levels.info;

}

static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level)

{

#ifndef HAVE_ANDROID_OS

return false;

#else /* HAVE_ANDROID_OS */

int len;

char key[PROPERTY_KEY_MAX];

char buf[PROPERTY_VALUE_MAX];

if (tag == NULL) {

return false;

}

jboolean result = false;

const char* chars = env->GetStringUTFChars(tag, NULL);

if ((strlen(chars)+sizeof(LOG_NAMESPACE)) > PROPERTY_KEY_MAX) {

jclass clazz = env->FindClass("java/lang/IllegalArgumentException");

char buf2[200];

snprintf(buf2, sizeof(buf2), "Log tag \"%s\" exceeds limit of %d characters\n",

chars, PROPERTY_KEY_MAX - sizeof(LOG_NAMESPACE));

// release the chars!

env->ReleaseStringUTFChars(tag, chars);

env->ThrowNew(clazz, buf2);

return false;

} else {

strncpy(key, LOG_NAMESPACE, sizeof(LOG_NAMESPACE)-1);

strcpy(key + sizeof(LOG_NAMESPACE) - 1, chars);

}

env->ReleaseStringUTFChars(tag, chars);

len = property_get(key, buf, "");

int logLevel = toLevel(buf);

return (logLevel >= 0 && level >= logLevel) ? true : false;

#endif /* HAVE_ANDROID_OS */

}

/*

* In class android.util.Log:

* public static native int println_native(int buffer, int priority, String tag, String msg)

*/

static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,

jint bufID, jint priority, jstring tagObj, jstring msgObj)

{

const char* tag = NULL;

const char* msg = NULL;

if (msgObj == NULL) {

jclass npeClazz;

npeClazz = env->FindClass("java/lang/NullPointerException");

assert(npeClazz != NULL);

env->ThrowNew(npeClazz, "println needs a message");

return -1;

}

if (bufID < 0 || bufID >= LOG_ID_MAX) {

jclass npeClazz;

npeClazz = env->FindClass("java/lang/NullPointerException");

assert(npeClazz != NULL);

env->ThrowNew(npeClazz, "bad bufID");

return -1;

}

if (tagObj != NULL)

tag = env->GetStringUTFChars(tagObj, NULL);

msg = env->GetStringUTFChars(msgObj, NULL);

int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);

if (tag != NULL)

env->ReleaseStringUTFChars(tagObj, tag);

env->ReleaseStringUTFChars(msgObj, msg);

return res;

}

/*

* JNI registration.

*/

static JNINativeMethod gMethods[] = {

/* name, signature, funcPtr */

{ "isLoggable", "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable },

{ "println_native", "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native },

};

int register_android_util_Log(JNIEnv* env)

{

jclass clazz = env->FindClass("android/util/Log");

if (clazz == NULL) {

LOGE("Can't find android/util/Log");

return -1;

}

levels.verbose = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "VERBOSE", "I"));

levels.debug = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "DEBUG", "I"));

levels.info = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "INFO", "I"));

levels.warn = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "WARN", "I"));

levels.error = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "ERROR", "I"));

levels.assert = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "ASSERT", "I"));

return AndroidRuntime::registerNativeMethods(env, "android/util/Log", gMethods, NELEM(gMethods));

}

}; // namespace android

3. runtime library liblog

int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)

{

struct iovec vec[3];

if (!tag)

tag = "";

/* XXX: This needs to go! */

if (!strcmp(tag, "HTC_RIL") ||

!strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */

!strcmp(tag, "AT") ||

!strcmp(tag, "GSM") ||

!strcmp(tag, "STK") ||

!strcmp(tag, "CDMA") ||

!strcmp(tag, "PHONE") ||

!strcmp(tag, "SMS"))

bufID = LOG_ID_RADIO;

vec[0].iov_base = (unsigned char *) &prio;

vec[0].iov_len = 1;

vec[1].iov_base = (void *) tag;

vec[1].iov_len = strlen(tag) + 1;

vec[2].iov_base = (void *) msg;

vec[2].iov_len = strlen(msg) + 1;

return write_to_log(bufID, vec, 3);

}

static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);

static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;

static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)

{

#ifdef HAVE_PTHREADS

pthread_mutex_lock(&log_init_lock);

#endif

if (write_to_log == __write_to_log_init) {

log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY);

log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY);

log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY);

log_fds[LOG_ID_SYSTEM] = log_open("/dev/"LOGGER_LOG_SYSTEM, O_WRONLY);

write_to_log = __write_to_log_kernel;

if (log_fds[LOG_ID_MAIN] < 0 || log_fds[LOG_ID_RADIO] < 0 ||

log_fds[LOG_ID_EVENTS] < 0) {

log_close(log_fds[LOG_ID_MAIN]);

log_close(log_fds[LOG_ID_RADIO]);

log_close(log_fds[LOG_ID_EVENTS]);

log_fds[LOG_ID_MAIN] = -1;

log_fds[LOG_ID_RADIO] = -1;

log_fds[LOG_ID_EVENTS] = -1;

write_to_log = __write_to_log_null;

}

if (log_fds[LOG_ID_SYSTEM] < 0) {

log_fds[LOG_ID_SYSTEM] = log_fds[LOG_ID_MAIN];

}

}

#ifdef HAVE_PTHREADS

pthread_mutex_unlock(&log_init_lock);

#endif

return write_to_log(log_id, vec, nr);

}

...