|Job| Application No Response Analysis

ANR 的發生情形,通常是時間到了還沒有回應!所以掌握這個想法,就比較好找 Code。

比較常見有三種情形:

  1. Service Timeout
  2. BroadcastQueue Timeout
  3. ContentProvider Timeout

 

Case 1. Service Timeout

 a. Service 啟動後,會發送 SERVICE_TIMEOUT_MSG 消息
 b. Service 刪除後,就會刪除 SERVICE_TIMEOUT_MSG 消息
 c. 如果 SERVICE_TIMEOUT_MSG 未删除,時間到後就會 ANR

 呼叫 ActiveServices 的 serviceTimeout 方法進行處理,
 serviceTimeout方法邏輯:

 if (anrMessage != null) {
  mAm.appNotResponding(proc, null, null, false, anrMessage);
 }

 

Case 2. BroadcastQueue Timeout

 BroadcastQueue 中的 mHandler 收到 BROADCAST_TIMEOUT_MSG 消息時會觸發

 // 正常要發送消息前
 broadcastTimeoutLocked(false);

 // 發送消息,鎖住
 case BROADCAST_TIMEOUT_MSG: {
  synchronized (mService) {
   broadcastTimeoutLocked(true);

 // ANR
 在 broadcastTimeoutLocked 方法中,首先取得 anrMessage 字串

 anrMessage = “Broadcast of ” + r.intent.toString();

 mHandler.post(new AppNotResponding(app, anrMessage));
 mService.appNotResponding(mApp, null, null, false, mAnnotation);

 

Case 3. ContentProvider Timeout

 MainHandler 的 handleMessage CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG

 private final void processContentProviderPublishTimedOutLocked(ProcessRecord app) {
cleanupAppInLaunchingProvidersLocked(app, true);
 removeProcessLocked(app, false, true, “timeout publishing content providers”);
 }

 app.kill(reason, true);

 

ref.

https://blog.csdn.net/u012439416/article/category/7261623

 

|Jobs| How to write your own daemon?

要怎樣寫一個服務:他能夠

在一開機啟動、

不易死掉(你可以寫 script 一直啟動他)、

fork() 後終止父行程並和呼叫的終端機(TTY)脫離關係?

 

首先,我們可以寫個服務(執行檔或是一個 script),處理我們要做的事。

接著,我們再準備一個script,放到正確的位置。而這份草稿他的目的最主要就是: 告訴系統,在一開機啟動我們的服務!

以下最主要就是介紹這個 script 該如何寫:



.Method 1: traditional

1. WRITE: /etc/init.d/triggerd
    to run script or daemon: $TRIGGERD_HOME/bin/triggerMyService.sh

 #!/bin/bash
 start_triggerd=$TRIGGERD_HOME/bin/triggerMyService.sh
 stop_triggerd=$TRIGGERD_HOME/bin/triggerMyService.sh

 start() {
  echo -n “Starting MyService”
 }

 stop() {
  echo -n “Shutdown MyService”
 }

 #how we were called
 case “$1” in
  start)
     start
   ;;
  stop)
   stop
   ;;
  restart)
   stop
   sleep 10
   start
   ;;
  *)
   echo “Usage: $0 {start|stop|restart}”
 esac
 exit 0


2. chmod 777 /etc/init.d/triggerd



.Method 2: systemctl

1. 建立一個名為 triggerd.service 的系統服務指令碼
 vim /usr/lib/systemd/system/triggerd.service

 [Unit]
 Description=triggerMyService.sh

 [Service]
 Type=forking
 PIDFile=…
 Environment=CATALINA_HOME=/usr/local/triggerMyService.sh

 ExecStart=/usr/local/triggerMyService.sh start
 ExecStop=/usr/local/triggerMyService.sh stop
 User=…
 Group=…
 PrivateTmp=true

 [Install]
 WantedBy=multi-user.target

2. 重新載入一下配置
 systemctl daemon-reload

3. 設定允許開機自啟動
 systemctl enable triggerd

 #啟動服務
 systemctl start triggerd

 

ref.

創建 Daemon 程式

start-stop-daemon 啟動停止系統守護進程

[開機啟動]Linux開機自啟和運行級別

centos7下配置Tomcat開機啟動(service方式和daemon方式)

Linux systemd 寫 可自動啟動的 Daemon Service

 

|Tools| Useful Linux Commands

.在特定類型的文件裡找字串
grep -ir “ooxx“ –include=”*.java”

.掛載外接硬碟
sudo fdisk -l
mkdir /media/usb
sudo mount -v -t auto /dev/sdb1 /media/usb

.找特定類型的檔案

find -iname *.git

|Jobs| 系統廠工程師需要具備的 Linux 相關知識

  • IPC 溝通有許多方式(兩個 process 互相交換資料的方法)
  • 何時要開 proccess,何時用 multi-thread 就好
  • In C language, system()
  • Makefile 如何寫
  • 系統默認路徑
    • Include 系統默認搜尋範圍: /usr/include/usr/local/include
    • Lib 預設目錄: /lib、/usr/lib、/usr/local/lib
      • 環境變數 LD_LIBRARY_PATH 中指向搜索路徑
      • /etc/ld.so.conf 文件中增加搜索目錄
    • 執行檔預設目錄: 如果不加 ./ ,預設是執行 /bin、/usr/bin

|Code| 如何在 C++ 程式使用 C api ?

C++ 可以引用其他 C語言寫的 api,這不意外。

但要怎麼做?

C++:

請在把要使用的 C api 的 header 用 extern “C” 包起來

extern "C"
{
#include "demo_c_api_A.h"
#include "demo_c_api_B.h"
}

 

而要被使用的 C api 的 header:

demo_c_api_A.h:

#ifndef DEMO_C_API_A_H
#define DEMO_C_API_A_H

#include "aaa.h"
#include <bbb.h>

#ifdef __cplusplus
extern "C"
{
#endif

...

(C 的 header 原本該寫的東西)

...

#ifdef __cplusplus
}
#endif

#endif

 

你也可以不要直接用 extern 標全部,單獨寫:

#ifndef DEMO_C_API_A_H
#define DEMO_C_API_A_H

#include "aaa.h"
#include <bbb.h>

extern int c_api_A_init();


(C 的 header 原本該寫的東西)

#endif
#endif

 

 

延伸:extern 是什麼?

ref. Why use #ifndef CLASS_H and #define CLASS_H in .h file but not in .cpp?

|Issue| dlopen ERROR: undefined symbol

我們可以利用 dlopen 載入動態函式庫,然後使用 dlsym 取得裡面的函式來使用。

這兩個方法使用方式可以參考:dlopen&dlsym 用法

有遇到載入失敗,出現:undefined symbol

後面接著一串很像函式名稱的東西。

那時候我猜測是有兩種可能:我函式有問題 (可是 compiler 應該不會過才對),或者,

沒有正確連結?

我使用 nm 去驗證我的想法。

nm 可以列出目標的所有 symbol,看是不是那個函式有在裏面,但有問題?還是那個函式真的沒有在裡面?

在 cmd line 執行:nm -C -D bad_lib.so

就會列出全部的 symbol。其中,-D 指的是察看的對象是動態檔唷!

 

還有一個小工具:ldd 順便介紹一下。

ldd (List Dynamic Dependencies) 可以尋找所使用的函式庫!

執行:ldd (選項) (參數)

就可以列出全部被用到的函式庫啦!

 

ref.

解決 undefined symbol / reference

 

|Issue| 將 .a 包進 .so後,無法使用 .so

Segmentation fault

–whole-archive:可以強制將每個對象包含在生成的共享函式庫裡

所以我把我要包進 .so 的 .a lib 都加上了這個參數

總算可以開啟 .so

*在 static 库中,连接器将停止在第一个符号,即使它是一个弱的,并停止寻找强大的。若要强制它查看所有符号( 就像对动态链接库所做的那样),ld 支持 --whole-archive 选项。

 

ref.

https://ask.helplib.com/others/post_12552910

|Code| Makefile 參數介紹

Makefile 裡面最複雜的就是很多符號以及參數不明白意思。

這邊稍微介紹一下。

跟編譯過程有關:

  • -c:編譯但不進行鏈結,會產生一個跟原始碼相同名字的 .o 檔
  • -O:表示最佳化的程度
  • -g:要包含偵錯資訊

跟連結有關:

  • -l :編譯過程需要一個 library。e.g. -lpthread 表示需要 libpthread.so 函式庫
  • -L:需要鏈結庫外部人家已經寫好的函式的目錄
  • -I : 優先搜尋的 include 檔案路徑

跟包成的目標函式庫有關:

  • -shared:如果目標為動態函式/共享函式庫,一定要加
  • -fPIC:包成動態函式
  • -static:包成靜態函式庫

其他字元:

%.o: %.cpp
g++ -Wall -g -c $^
  • $^:所有的必要條件(%.cpp)
  • $@:工作目標(%.o)
  • %:一個萬用字元,

e.g.:%.o: %.c 這一行,就會知道如果現在的工作目標是 demo.o 的話,就會去找對應的 demo.c

  • $<:第一個必要條件(%.cpp,本例子中只有一個必要條件)

傳遞參數:

  • -Wa : 將選項 (option) 傳給組譯器
  • -wl : 將選項 (option) 傳給連結器

備註:

*編譯不連結,表示只檢查 include 裡有沒有宣告,並不會去相關 lib 找函式真的是否存在

*動態函式跟共享函式差別在於:動態函式程式執行時期並不會去檢查該函式是否存在,而是程式執行到某功能時才進行檢查。

*編譯時,利用 -L 告訴編譯器可以該路徑下尋找 libpthread.so。

若使用了-l,則必須使用的 lib 在預設尋找的目錄中,

保險起見,可以利用 -L 指定多個路徑給編譯器。

ref.

http://maxubuntu.blogspot.com/2010/02/makefile.html

[Linux] 簡單的 Makefile 使用 (% 萬用字元、$@ 特殊符號、.PHONY 假目標)

WordPress.com.

Up ↑