標籤:pthread inf print strlen except 技術 hone 寫入 unsigned
這幾天和華為的leader面試了下。感覺不錯。關鍵是小女。不容易。是技術面啊。我說的不容易不是面試不容易,是說在華為寫代碼的小女不容易。哥走南闖北這麼多年,女人代碼寫的好真不多。
其實在任何時候,只要一面試都感覺自己會的少。都這樣。那隻能不斷的增強能力。開始重點轉入native code的學習。今天和大家聊聊log機制,這個東西也不容易。今天只談談log如何被寫到驅動裡,
有人說這個比較容易,要打log,在java裡直接Log.d Log.i Log.e就可以了。嗯,不錯,那問題來了。
1 java是如何把資料寫到了裝置裡呢?
2 如何在native程式中打log呢?
自古華山一條路,看code吧。
public static int d(String tag, String msg) {
return println_native(LOG_ID_MAIN, DEBUG, tag, msg);
}
不看不知道,一看嚇一跳,原來這些資料通過j//marvell 臧春傑ni直接寫到了裝置裡了。看看jni是如何寫入的把
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) {
jniThrowNullPointerException(env, "println needs a message");
return -1;
}
if (bufID < 0 || bufID >= //marvell 臧春傑LOG_ID_MAX) {
jniThrowNullPointerException(env, "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;
}
這就比較清楚了,清楚了參數的含義。資料寫到了哪個裝置裡?
crw-rw-rw- root log 10, 36 1970-01-01 16:42 events
crw------- root log 10, 33 1970-01-01 16:42 kernel
crw-rw-rw- root log 10, 37 1970-01-01 16:42 main
crw-rw-rw- root log 10, 35 1970-01-01 16:42 radio
crw-rw-rw- root log 10, 34 1970-01-01 16:42 system
優先順序怎麼樣的, 訊息的tag是什嗎? 寫了什麼資料。 到這裡我們日然沒看到寫裝置節點啊。不管怎麼說, jni通過getStringUTFChars擷取了java層的字串。
int __android_log_buf_write(int bu//marvell 臧春傑fID, int prio, const char *tag, const char *msg)
{
struct iovec vec[3];
char tmp_tag[32];
if (!tag)
tag = "";
/* XXX: This needs to go! */
if ((bufID != LOG_ID_RADIO) &&
(!strcmp(tag, "HTC_RIL") ||
!strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
!strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
!strcmp(tag, "AT") ||
!strcmp(tag, "GSM") ||
!strcmp(tag, "STK") ||
!strcmp(tag, "CDMA") ||
//marvell 臧春傑
!strcmp(tag, "PHONE") ||
!strcmp(tag, "SMS"))) {
bufID = LOG_ID_RADIO;
/* Inform third party apps/ril/radio.. to use Rlog or RLOG */
snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
tag = tmp_tag;
}
if (prio == ANDROID_LOG_FATAL) {
android_set_abort_message(msg);
}
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);
}
這裡把所有的資訊放到了結構體數組裡,為什麼要放到結構體I數組呢? 我還不清楚。 這裡對bufferid和tag做了校正,Log類會把所有的資訊都寫到了/dev/main裝置裡。這裡把有些tag的資訊寫到了/dev/radio裝置中,也就是modem資訊
static int __write_to_log_init(log_id_t, struct //marvell 臧春傑 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)
{
pthread_mutex_lock(&log_init_lock);
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]);
//marvell 臧春傑
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];
}
}
pthread_mutex_unlock(&log_init_lock);
return write_to_log(log_id, vec, nr);
}
這裡google玩個小技巧,write_to_log = __write_to_log_init, 初始化以後改成了write_to_log = __write_to_log_kernel;
這裡開才是寫裝置節點。這樣,最後
int writev( int fd, const struct iovec* vecs, int count ) //cjzang
{
int total = 0;
for ( ; count > 0; count--, vecs++ ) {
const char* buf = vecs->iov_base;
int len = vecs->iov_len;
while (len > 0) {
int ret = write( fd, buf, len ); //marvell 臧春傑
if (ret < 0) {
if (total == 0)
total = -1;
goto Exit;
}
if (ret == 0)
goto Exit;
total += ret;
buf += ret;
len -= ret;
}
}
Exit:
return total;
}
就這樣,浪窪地寫進去了。啪啪啪的寫進去了。寫到驅動裡了。
那native code是如何加log呢? 他有時如何寫進的呢?
native要列印log需要做一下幾件事情,
1 包含標頭檔,那問題來了,我該包含哪個標頭檔呢? android 那麼大,那麼多標頭檔,要人老命,腰疼。需要包含system/core/include/log/log.h這個標頭檔。
#include <log/log.h> 同時需要在檔案中定義log_tag
然後再需要的地方加上
ALOGD("===========================");
然後需要在makefile中加上#LOCAL_SHARED_LIBRARIES := liblog
就可以了,其實看看裡面的實現,也是進入了
int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...)
{
va_list ap;
char buf[LOG_BUF_SIZE];
va_start(ap, fmt);
vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
va_end(ap);
return __android_log_buf_write(bufID, prio, tag, buf);
}
就這樣,log資訊就響應的寫到了具體I的裝置節點了。
不好整,整不好。
android log寫入機制