日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

android log.d 参数,Android log 机制 - logd 总览

發布時間:2024/7/23 Android 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android log.d 参数,Android log 机制 - logd 总览 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Android 早期版本使用的是一個 log 驅動,后來逐漸使用 logd 進程替代(具體哪個版本我就沒有去探究了,至少在 Android 8.0 里,log 驅動已經被移除)。原有 log 驅動負責的功能,都由 logd 完成。此外,logd 還可以讀取 Linux 內核 printk、selinux 的 log。

logd 的啟動

logd 是由 init 進程啟動的:

1

2

3

4

5

6

7

8

9

10

11

12# system/core/rootdir/init.rc

on post-fs

# Load properties from

# /system/build.prop,

# /odm/build.prop,

# /vendor/build.prop and

# /factory/factory.prop

load_system_props

# start essential services

start logd

start servicemanager

# ...

logd 的參數在 logd.rc 中:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24# system/core/logd/logd.rc

service logd /system/bin/logd

socket logd stream 0666 logd logd

socket logdr seqpacket 0666 logd logd

socket logdw dgram 0222 logd logd

file /proc/kmsg r

file /dev/kmsg w

user logd

group logd system readproc

writepid /dev/cpuset/system-background/tasks

service logd-reinit /system/bin/logd --reinit

oneshot

disabled

user logd

group logd

writepid /dev/cpuset/system-background/tasks

on fs

write /dev/event-log-tags "# content owned by logd

"

chown logd logd /dev/event-log-tags

chmod 0644 /dev/event-log-tags

restorecon /dev/event-log-tags

可以看到,init 進程會幫 logd 創建 3 個 Unix 域 socket,分別為 /dev/socket/logd, /dev/socket/logdr, /dev/socket/logdw。

創建 socket 系統調用原型如下:

1

2

3

4#include

#include

int socket(int domain, int type, int protocol);

init.rc 中的 stream, seqpacket, dgram 用于設置 socket 函數的第二個參數 type,分別對應 SOCK_STREAM, SOCK_SEQPACKET, SOCK_DGRAM。

SOCK_STREAM 提供的是可靠的流數據(類比于 TCP),SOCK_SEQPACKET 則提供可靠的基于包的數據(可靠的UDP),SOCK_DGRAM 可以用 UDP 來類比,不可靠的包傳輸。詳細信息可以查看 man page 了解。

當然,domain 參數是 PF_UNIX(估計寫著代碼的程序員比較老派,新的程序建議使用 AF_LOCAL,兩者沒有區別)。

這三個 socket 的功能如下:

socket logd 用于外接受控制命令

客戶端通過 logdr 讀取 log 數據。使用 seqpacket,可以讓用戶在可靠地讀取數據的同時,一次讀取一條 log

客戶端通過 logdw 寫入 log 數據。由于類型是 dgram,在非常繁忙的時候,log 可能會丟失。但是,這可以避免客戶端阻塞在寫 log 的調用上

logd 的初始化

init 進程啟動 logd 后,和其他程序一樣,首先執行的是 main 函數。main 函數的主要工作如下:

讀取系統屬性,判斷是否需要讀內核的 log (klog 和 selinux 的log)

初始化一些信號量,啟動 reinit 線程

啟動各個子服務,監聽上面我們提到的幾個 socket

如果需要讀內核 log,也監聽對應的 log

阻塞等待(main 函數不能退出,否則進程直接會退出,即便還有線程在運行)

下面我們一起看看他的 main 函數:

1

2

3

4

5

6

7

8

9// system/core/logd/main.cpp

int main(int argc, char* argv[]){

// issue reinit command. KISS argument parsing.

if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) {

return issueReinit();

}

// ...

}

在上面 init.rc 中,我們看到,正常啟動 logd 是不帶參數的,所以這里的 if 不會執行。當重新啟動時,帶 --reinit 參數。這里我們就假定是正常啟動。

1

2

3

4# system/core/logd/logd.rc

service logd /system/bin/logd

service logd-reinit /system/bin/logd --reinit

接下來獲取 /dev/kmsg 的描述符。這個文件用于跟內核的 log 系統通信。正常情況下,init 進程會幫我們打開。如果沒有,我們自己打開它。

1

2

3

4

5

6

7

8

9

10

11

12// system/core/logd/main.cpp

int main(int argc, char* argv[]){

// ...

static const char dev_kmsg[] = "/dev/kmsg";

fdDmesg = android_get_control_file(dev_kmsg);

if (fdDmesg < 0) {

fdDmesg = TEMP_FAILURE_RETRY(open(dev_kmsg, O_WRONLY | O_CLOEXEC));

}

// ...

}

接著,讀取系統屬性,判斷是否需要讀內核的 log。如果需要,就打開 /proc/kmsg。這個文件用于讀取內核 log。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20// system/core/logd/main.cpp

int main(int argc, char* argv[]){

// ...

int fdPmesg = -1;

bool klogd = __android_logger_property_get_bool(

"logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST |

BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE);

if (klogd) {

static const char proc_kmsg[] = "/proc/kmsg";

fdPmesg = android_get_control_file(proc_kmsg);

if (fdPmesg < 0) {

fdPmesg = TEMP_FAILURE_RETRY(

open(proc_kmsg, O_RDONLY | O_NDELAY | O_CLOEXEC));

}

if (fdPmesg < 0) android::prdebug("Failed to open %s\n", proc_kmsg);

}

// ...

}

默認情況下,會讀取內核 log。這里我們就直接假設 klogd 為 true。

跟著,啟動 reinit 線程:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38// system/core/logd/main.cpp

static sem_t uidName;

static uid_t uid;

static char* name;

static sem_t reinit;

static bool reinit_running = false;

static LogBuffer* logBuf = nullptr;

static sem_t sem_name;

int main(int argc, char* argv[]){

// ...

// Reinit Thread

sem_init(&reinit, 0, 0);

sem_init(&uidName, 0, 0);

sem_init(&sem_name, 0, 1);

pthread_attr_t attr;

if (!pthread_attr_init(&attr)) {

struct sched_param param;

memset(&param, 0, sizeof(param));

pthread_attr_setschedparam(&attr, &param);

pthread_attr_setschedpolicy(&attr, SCHED_BATCH);

if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {

pthread_t thread;

reinit_running = true;

if (pthread_create(&thread, &attr, reinit_thread_start, nullptr)) {

reinit_running = false;

}

}

pthread_attr_destroy(&attr);

}

// ...

}

sem_init 用于初始化 POSIX 信號量,它的原型如下:

1

2include

int sem_init(sem_t *sem, int pshared, unsigned int value);

pshared 參數控制是否在多個進程間共享。這里我們只是用于進程內部的通信,所以傳入 0。

在讀這段代碼的時候,有一個值得注意的是,pthread 在成功的時候返回 0,失敗則返回一個非 0 的錯誤碼(這一點跟一般的系統調用不同。一般的系統調用,失敗的情況下會返回 -1)。

舉例來說,中間用于判斷 pthread_create 是否成功的 if 語句,只有在線程創建失敗的時候才會執行。

1

2

3if (pthread_create(&thread, &attr, reinit_thread_start, nullptr)) {

reinit_running = false;

}

關于 reinit_thread_start 函數,后面我們遇到了再看它的具體內容。

下面判斷是否需要讀 selinux 的 log。然后,調用 drop_privs 函數根據是否讀取內核 log 設置一些權限。關于 drop_privs 函數,有興趣的讀者可以自行閱讀源碼,這部分并不會影響 logd 的邏輯。

1

2

3

4

5

6

7

8

9

10

11

12// system/core/logd/main.cpp

int main(int argc, char* argv[]){

// ...

bool auditd =

__android_logger_property_get_bool("ro.logd.auditd", BOOL_DEFAULT_TRUE);

if (drop_privs(klogd, auditd) != 0) {

return -1;

}

// ...

}

下面,實例化 LogBuffer 并注冊信號處理器。所有的 log 都會寫入這個 LogBuffer;當客戶端需要讀取 log 的時候,也從這個 LogBuffer 讀取。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26// system/core/logd/main.cpp

int main(int argc, char* argv[]){

// ...

// Serves the purpose of managing the last logs times read on a

// socket connection, and as a reader lock on a range of log

// entries.

LastLogTimes* times = new LastLogTimes();

// LogBuffer is the object which is responsible for holding all

// log entries.

logBuf = new LogBuffer(times);

signal(SIGHUP, reinit_signal_handler);

if (__android_logger_property_get_bool(

"logd.statistics", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST |

BOOL_DEFAULT_FLAG_ENG |

BOOL_DEFAULT_FLAG_SVELTE)) {

logBuf->enableStatistics();

}

// ...

}

現在,各種準備工作都完成了,啟動實際的工作線程:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62// system/core/logd/main.cpp

int main(int argc, char* argv[]){

// ...

// LogReader listens on /dev/socket/logdr. When a client

// connects, log entries in the LogBuffer are written to the client.

LogReader* reader = new LogReader(logBuf);

if (reader->startListener()) {

exit(1);

}

// LogListener listens on /dev/socket/logdw for client

// initiated log messages. New log entries are added to LogBuffer

// and LogReader is notified to send updates to connected clients.

LogListener* swl = new LogListener(logBuf, reader);

// Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value

if (swl->startListener(600)) {

exit(1);

}

// Command listener listens on /dev/socket/logd for incoming logd

// administrative commands.

CommandListener* cl = new CommandListener(logBuf, reader, swl);

if (cl->startListener()) {

exit(1);

}

// LogAudit listens on NETLINK_AUDIT socket for selinux

// initiated log messages. New log entries are added to LogBuffer

// and LogReader is notified to send updates to connected clients.

LogAudit* al = nullptr;

if (auditd) {

al = new LogAudit(logBuf, reader,

__android_logger_property_get_bool(

"ro.logd.auditd.dmesg", BOOL_DEFAULT_TRUE)

? fdDmesg

: -1);

}

LogKlog* kl = nullptr;

if (klogd) {

kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, al != nullptr);

}

readDmesg(al, kl);

// failure is an option ... messages are in dmesg (required by standard)

if (kl && kl->startListener()) {

delete kl;

}

if (al && al->startListener()) {

delete al;

}

// ...

}

在 logd 進程啟動的時候,內核很可能已經有 log 數據存在,readDmesg() 把已有的 log 讀出來放到 logBuffer 中。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42// system/core/logd/main.cpp

static void readDmesg(LogAudit* al, LogKlog* kl){

if (!al && !kl) {

return;

}

int rc = klogctl(KLOG_SIZE_BUFFER, nullptr, 0);

if (rc <= 0) {

return;

}

// Margin for additional input race or trailing nul

ssize_t len = rc + 1024;

std::unique_ptr buf(new char[len]);

rc = klogctl(KLOG_READ_ALL, buf.get(), len);

if (rc <= 0) {

return;

}

if (rc < len) {

len = rc + 1;

}

buf[--len] = '\0';

if (kl && kl->isMonotonic()) {

kl->synchronize(buf.get(), len);

}

ssize_t sublen;

for (char *ptr = nullptr, *tok = buf.get();

(rc >= 0) && !!(tok = android::log_strntok_r(tok, len, ptr, sublen));

tok = nullptr) {

if ((sublen <= 0) || !*tok) continue;

if (al) {

rc = al->log(tok, sublen);

}

if (kl) {

rc = kl->log(tok, sublen);

}

}

}

klogctl 是 Linux 內核特有的系統調用,用于讀取、設置內核 log,原型如下,詳情可以查看 man page:

1

2#include

int klogctl(int type, char *bufp, int len);

第一個 klogctl 的 type 為 KLOG_SIZE_BUFFER,該調用返回內核 log 緩沖的總長度。

值得注意的是,查看 man page 時,man page 里對應的常量為 KLOG_ACTION_**。這些常量跟 KLOG_** 是一一對應的:

1

2

3

4

5

6

7

8

9

10

11

12

13

14// platform/bionic/libc/include/sys/klog.h

/* These correspond to the kernel's SYSLOG_ACTION_whatever constants. */

#define KLOG_CLOSE 0

#define KLOG_OPEN 1

#define KLOG_READ 2

#define KLOG_READ_ALL 3

#define KLOG_READ_CLEAR 4

#define KLOG_CLEAR 5

#define KLOG_CONSOLE_OFF 6

#define KLOG_CONSOLE_ON 7

#define KLOG_CONSOLE_LEVEL 8

#define KLOG_SIZE_UNREAD 9

#define KLOG_SIZE_BUFFER 10

第二個 klogctl 使用 KLOG_READ_ALL 讀取所有的 log。隨后,使用 LogAudit, LogKlog 講讀取到的 log 寫入 LogBuffer。

最后,main 函數在 pause() 上永久等待。這是因為,如果 main 函數退出,進程就會退出(即使沒有最后那個 exit(0),main 函數返回也會導致進程退出)。

1

2

3

4

5

6

7

8

9

10// system/core/logd/main.cpp

int main(int argc, char* argv[]){

// ...

TEMP_FAILURE_RETRY(pause());

exit(0);

// ...

}

logd 的啟動到這里就結束了,實際的 log 讀寫邏輯,后面再一一分析。

總結

以上是生活随笔為你收集整理的android log.d 参数,Android log 机制 - logd 总览的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产日批视频 | 日韩精品啪啪 | 午夜之声l性8电台lx8电台 | 五月天小说网 | 欧美男同又粗又长又大 | 欧美裸体网站 | 性生活毛片 | 在线少妇 | 不卡视频免费在线观看 | www99热| 2024男人天堂 | 青青射 | 精品人伦一区二区三区蜜桃网站 | 亚洲欧美日韩免费 | 狠狠操夜夜| 在线观看的毛片 | 亚洲欧洲免费无码 | 偷拍亚洲精品 | 国产精品美女久久久久av超清 | 裸体喂奶一级裸片 | av大片在线看 | 免费成人av| 日韩欧美精品一区二区 | 久久久99精品国产一区二区三区 | 精品国产一级久久 | 五月在线视频 | 黄色不卡| 天天干天天谢 | 欧美日韩精品一区二区三区蜜桃 | www.xxx日韩| 国产人妻一区二区三区四区五区六 | 91成人在线观看高潮 | 精品国产精品国产偷麻豆 | 草草久久久无码国产专区 | 精品理论片 | 日韩中文字幕视频在线观看 | 久久精品首页 | 欧美成人一区二区三区片免费 | 欧美一区二区黄色 | 日韩av中文在线 | 福利资源在线 | 一区二区久久精品66国产精品 | 在线观看中文字幕码 | 亚洲av无码电影在线播放 | 亚州一级 | av夜夜操| 天天躁日日躁aaaa视频 | 91老师国产黑色丝袜在线 | 少妇人妻无码专区视频 | 中文字幕999| 亚洲69视频 | 波多野结av衣东京热无码专区 | 欧美日韩在线成人 | 久久夜夜操妹子 | 91亚洲视频 | 天天干天天摸 | 丨国产丨调教丨91丨 | 三区四区 | 奇米影视777四色 | 日韩黄色在线视频 | 久久久999国产精品 天堂av中文在线 | 国产对白自拍 | 精品久久福利 | 蜜臀av性久久久久蜜臀av麻豆 | 亚洲色吧 | 91精品国产高清一区二区三密臀 | 国产又粗又猛又黄又爽的视频 | av无码精品一区二区三区宅噜噜 | 国产主播一区 | 天天曰天天 | 男男做性免费视频网 | 色哟哟一区二区 | 欧美妞干网| 国产一区二区三区观看 | 91精品一区二区三区综合在线爱 | 国产69精品久久久久999小说 | 一级大片网站 | 日韩视频在线观看视频 | 无码精品人妻一区二区三区影院 | 国产精品天天操 | 人妖天堂狠狠ts人妖天堂狠狠 | 丰满人妻一区二区三区四区 | 国产九九九九九 | 日韩美女爱爱 | 亚洲精品无码一区二区 | 上海毛片 | 天天综合视频 | 国产一区麻豆 | 亚洲女人天堂网 | 久久大| 欧美一区永久视频免费观看 | 亚洲国产av一区二区 | 国产精品96| 激情小说亚洲色图 | av波多野吉衣 | 99热这里都是精品 | 污片网站在线观看 | 毛片久久久久久 | 国产精品羞羞答答在线观看 |