2014/10/16

[轉]基礎 Linux Device Driver 驅動程式#10 (select/poll)

備份好文章
http://csw-dawn.blogspot.tw/2012/01/linux-device-driver-10-selectpoll.html


基礎 Linux Device Driver 驅動程式#10 (select/poll)

相信各位都有在Linux上寫程式的經驗,
當您程式裡呼叫 open 時,Linux 預設會以 blocking mode的方式開啟,
block 是指當 process 為了等待某件事的發生,而進入 sleep 狀態的情形。

像 read 就是其中一種,當沒資料讀取時,process 就會被 block。
write 也是一樣,在寫入資料時,寫入對象還無法處理資料時,一樣會 block。

對某些程式來說,如果 read 系統呼叫被 block 的話,有時就會有設計上的問題,
所以為了避免這種問題發生,Linux 就準備了以下方式。

1. Non-blocking 模式

啟用 non-blocking 模式後,不管是 read 還是 write 就不會被 block住。但會傳回 errno 錯誤碼,
這時就必須自已再做讀寫的動作。
想使用 non-blocking 模式的話,可在 open() 開檔時指定 O_NONBLOCK。

2. 同時執行多個同步 I/O 工作

同時執行多個同步 I/O 工作 指的是使用 select 系統呼叫的做法。
select 系統呼叫本身會被 block, 但可指定 timeout。

使用 select() 的時候,有幾個常用的函式巨集,可參考 man 2 select。

int select(int nfds, fd_set *readfds, fd_set *writefds,    fd_set *exceptfds, struct timeval *timeout);void FD_CLR(int fd, fd_set *set);int  FD_ISSET(int fd, fd_set *set);void FD_SET(int fd, fd_set *set);void FD_ZERO(fd_set *set);

還有一個和 select()很類似的 poll()系統呼叫,以基本功能來說,select()與poll()都一樣,
但指定的 file handler的方式不一樣,且指定多個 file handler 的時候,poll()走訪所有
file handler的速度比較快。 可參考 man 2 poll。

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

應用程式想同時執行多個同步 I/O 工作時,可使用的系統呼叫有好幾個,
但在驅動程式,只需要準備一個函式即可。
不管 user process 用了哪個系統呼叫,kernel 都只會呼叫驅動程式提供的這個函式。

Character 類型的裝置想支援同時執行多個同步 I/O 工作的話,只要在驅動程式準備 poll方法即可。
poll方法會收到 file_operations 結構。

unsigned int (*poll) (struct file *, struct poll_table_struct *);

poll方法會在kernel 處理 select 與 poll 之類的系統呼叫時用到。它必須的執行工作如下:
1. 在 wait queue 豋記。
2. 傳回目前可以操作的狀態。

在呼叫同時執行多個同步 I/O 工作的系統呼叫時,block 直到狀態變化的動作,指的是在 kernel裡面 sleep。
如果要 sleep的話,要先準備 wait queue(wait_queue_head_t),這個由驅動程式負責提供。
豋記 wait queue 的工作可透過 poll_wait()完成,它定義在 include/linux/poll.h

void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p);// filp:執行操作的設備文件指針// wait_address:設備驅動的等待隊列頭// p:內核傳遞的輪詢表指針 調用poll_wait()函數將等待隊列添加到poll_table輪詢表 (出處參考)

在呼叫同時執行多個同步 I/O 工作的系統呼叫時,解除 block 的時機,是驅動程式透過傳給 poll_wait()
的 wait queue 被喚醒的時候。Kernel 在被 wait queue 喚醒之後,會再次呼叫驅動程式的 poll()
確認是否成為等待中的狀態(可寫入或可讀出),如果是的話,FD_ISSET 巨集就會成立。
想判斷是不是這種狀態的話,還是需要驅動程式提供資訊才行,這個資訊就是透過poll()方法的傳回值來表示。
傳回值要透過 include/linux/poll.h 定義的巨集 OR 起來表示,下面是常用到的組合。
數值定義於 android/bionic/libc/kernel/arch-arm/asm/poll.h

POLLIN|POLLRDNORM                     可讀取POLLOUT|POLLWRNORM                    可寫入POLLIN|POLLRDNORM|POLLOUT|POLLWRNORM  可讀寫POLLERR                               發生錯誤POLLHUP                               裝置離線(EOF)

說了那麼多,還倒不如寫個程式比較好了解。

poll操作一般結構:

xxx_poll() {   unsigned int mask = 0;//定義返回值   ...   //調用poll_wait()把進程添加到輪詢表   ...   if(device is ready for read){     mask = POLLIN | POLLRDNORM;   }   ...   return mask; } 

剛試了一下,果然新舊版核心還是有差,幾個問題,稍為提出來討論一下:
1. 要用 kmalloc 及 kfree 的話,要 include 註:其實在上一個示範程式就已有這問題了。
請參考: 基礎 Linux Device Driver 驅動程式#9 (IOCTL)
2. void init_MUTEX (struct semaphore *sem); /* 新版 kernel 已不適用 */
改用
void sema_init (struct semaphore *sem, int val);

test_select.c 原始碼如下:

/*****************************************************************************/#include #include #include #include #include #include #include #include #include #include #include #define DRIVER_NAME "test_select"static unsigned int test_select_major = 0;static unsigned int num_of_dev = 1;static struct cdev test_select_cdev;static unsigned int timeout_value = 10;struct test_select_data { struct timer_list timeout; spinlock_t lock; wait_queue_head_t read_wait; int timeout_done; struct semaphore sem;};unsigned int test_select_poll(struct file *filp, poll_table *wait){ struct test_select_data *data = filp->private_data; unsigned int mask = POLLOUT|POLLWRNORM; printk(KERN_ALERT "Call test_select_poll.\n"); if (data == NULL)  return -EBADFD; down(&data->sem); poll_wait(filp, &data->read_wait, wait); if (data->timeout_done == 1) {    /* readable */  mask |= POLLIN|POLLRDNORM; } up(&data->sem); printk(KERN_ALERT "%s returned (mask 0x%x)\n", __func__,  mask);}static void test_select_timeout(unsigned long arg){ struct test_select_data *data = (struct test_select_data*)arg; unsigned long flags; printk(KERN_ALERT "Call test_select_timeout.\n"); spin_lock_irqsave(&data->lock, flags); data->timeout_done = 1; wake_up_interruptible(&data->read_wait); spin_unlock_irqrestore(&data->lock, flags);}ssize_t test_select_write (struct file *filp, const char __user *buf, size_t count, loff_t *pos){ return -EFAULT;}ssize_t test_select_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos){ struct test_select_data *data = filp->private_data; int i; unsigned char val; int retval; if (down_interruptible(&data->sem))  return -ERESTARTSYS; if (data->timeout_done == 0) {    /* no read */  up(&data->sem);  if (filp->f_flags & O_NONBLOCK)    /* non-blocking mode */   return -EAGAIN;  do {   retval = wait_event_interruptible_timeout(       data->read_wait,       data->timeout_done == 1,       1*HZ);   if (retval == -ERESTARTSYS)    return -ERESTARTSYS;  } while (retval == 0);    /* timeout elapsed */  if (down_interruptible(&data->sem))   return -ERESTARTSYS; } val = 0xff; for (i = 0; i < count; i++) {  if (copy_to_user(&buf[i], &val, 1)) {   retval = -EFAULT;   goto out;  } } retval = count;out: data->timeout_done = 0;  /* restart timer */ mod_timer(&data->timeout, jiffies + timeout_value*HZ); up(&data->sem); return retval;}static int test_select_close(struct inode *inode, struct file *filp){ struct test_select_data *data = filp->private_data; printk(KERN_ALERT "Call test_select_close.\n"); if (data) {  del_timer_sync(&data->timeout);  kfree(data); } return 0;}static int test_select_open(struct inode *inode, struct file *filp){ struct test_select_data *data; printk(KERN_ALERT "Call test_select_open.\n"); data = kmalloc(sizeof(struct test_select_data), GFP_KERNEL); if (data == NULL)  return -ENOMEM; /* initialize members */ spin_lock_init(&data->lock); init_waitqueue_head(&data->read_wait); // init_MUTEX(&data->sem); /* 新版 kernel 已不適用 */ sema_init(&data->sem, 1);  /* 改用 sema_init */ init_timer(&data->timeout); data->timeout.function = test_select_timeout; data->timeout.data = (unsigned long)data; filp->private_data = data; /* start timer */ data->timeout_done = 0; mod_timer(&data->timeout, jiffies + timeout_value*HZ); return 0;}struct file_operations fops = { .owner = THIS_MODULE, .open = test_select_open, .release = test_select_close, .read = test_select_read, .write = test_select_write, .poll = test_select_poll,};static int test_select_init(void){ dev_t dev = MKDEV(test_select_major, 0); int alloc_ret = 0; int cdev_ret = 0; alloc_ret = alloc_chrdev_region(&dev, 0, num_of_dev, DRIVER_NAME); if (alloc_ret)  goto error; test_select_major = MAJOR(dev); cdev_init(&test_select_cdev, &fops); cdev_ret = cdev_add(&test_select_cdev, dev, num_of_dev); if (cdev_ret)  goto error; printk(KERN_ALERT "%s driver(major: %d) installed.\n", DRIVER_NAME, test_select_major);  return 0;error: if (cdev_ret == 0)  cdev_del(&test_select_cdev); if (alloc_ret == 0)  unregister_chrdev_region(dev, num_of_dev);  return -1;}static void test_select_exit(void){ dev_t dev = MKDEV(test_select_major, 0); cdev_del(&test_select_cdev); unregister_chrdev_region(dev, num_of_dev);  printk(KERN_ALERT "%s driver removed\n", DRIVER_NAME);}module_init(test_select_init);module_exit(test_select_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Wang Chen Shu");MODULE_DESCRIPTION("This is test_select module.");/*****************************************************************************/

Makefile 如下:

/*****************************************************************************/KDIR="/opt/linux-source-2.6.38"PWD=$(shell pwd)obj-m := test_select.oall: $(MAKE) -C ${KDIR} M=${PWD} modulesclean: $(MAKE) -C ${KDIR} M=${PWD} clean

/*****************************************************************************/

test.c 如下:
/*****************************************************************************/

#include #include #include #define DEVFILE "/dev/test_select0"int main(){ int fd;        fd_set rfds;        struct timeval tv;        int retval;        unsigned char buf;        ssize_t sz;        int i;        fd = open(DEVFILE, O_RDWR);        if (fd == -1) {                perror("open");                return -1;        }        do {                FD_ZERO(&rfds);                FD_SET(fd, &rfds);                tv.tv_sec = 5;                tv.tv_usec = 0;                printf("select() ...\n");                retval = select(fd + 1, &rfds, NULL, NULL, &tv);                if (retval == -1) {                        perror("select");                        break;                }                if (retval) {                        break;                }        } while (retval == 0);   /* timeout elapsed */        if (FD_ISSET(fd, &rfds)) {                printf("read() ...\n");                sz = read(fd, &buf, 1);                printf("read() %d\n", sz);                printf("%02x ", buf);                printf("\n");        }        close(fd);        return 0;}

/*****************************************************************************/

執行結果如下:

# ls
Makefile test_code test_select.c
# make
make -C “/opt/linux-source-2.6.38” M=/opt/test_driver/my_driver/test_select modules
make[1]: Entering directory `/opt/linux-source-2.6.38′
CC [M] /opt/test_driver/my_driver/test_select/test_select.o
/opt/test_driver/my_driver/test_select/test_select.c: In function ‘test_select_poll’:
/opt/test_driver/my_driver/test_select/test_select.c:44:1: warning: control reaches end of non-void function
Building modules, stage 2.
MODPOST 1 modules
CC /opt/test_driver/my_driver/test_select/test_select.mod.o
LD [M] /opt/test_driver/my_driver/test_select/test_select.ko
make[1]: Leaving directory `/opt/linux-source-2.6.38′
# ls
Makefile Module.symvers test_select.c test_select.mod.c test_select.o
modules.order test_code test_select.ko test_select.mod.o
# cd test_code/
# ls
test.c
# gcc test.c -o test
# ls
test test.c
# cd ..
# insmod ./test_select.ko
test_select driver(major: 250) installed.
# mknod /dev/test_select0 c 250 0
# ./test_code/test
select() …
read() …
… 經過 10秒 …
read() 1
ff
# dmesg | tail
… 以上略過 …
Call test_select_open.
Call test_select_poll.
test_select_poll returned (mask 0x104)
Call test_select_timeout.
Call test_select_close.

# rm -rf test_code/test
# rm /dev/test_select0
# rmmod test_select
# make clean
make -C “/opt/linux-source-2.6.38” M=/opt/test_driver/my_driver/test_select clean
make[1]: Entering directory `/opt/linux-source-2.6.38′
CLEAN /opt/test_driver/my_driver/test_select/.tmp_versions
CLEAN /opt/test_driver/my_driver/test_select/Module.symvers
make[1]: Leaving directory `/opt/linux-source-2.6.38′

OK, 一切就是如此的順利,世界就是如此的美好 ^^

註記及聲明:
本教學,是參考Linux Device Driver Programming驅動程式設計由平田豐著的這本書。

寫了一個修改route的batch檔 for Windows O.S

在windows寫一個batch檔控制route table路由
紀錄如下,

我會將電腦連接到另一外網, 而原本預設的gateway 10.55.11.253 要清掉
改成 10.x.x.x 與 110.x.x.x 的IP網址才經由 10.55.11.253 gateway出去
其他預設則皆由外網出去 (未加入batch裡)

@echo offcls:startecho ----------------------------------echo delete 0.0.0.0 mask 0.0.0.0 10.55.11.253route delete 0.0.0.0 mask 0.0.0.0 10.55.11.253echo delete 10.0.0.0 mask 255.0.0.0 10.55.11.253route delete 10.0.0.0 mask 255.0.0.0 10.55.11.253echo delete 110.0.0.0 mask 255.0.0.0 10.55.11.253route delete 110.0.0.0 mask 255.0.0.0 10.55.11.253echo add 10.0.0.0 mask 255.0.0.0 10.55.11.253route add 10.0.0.0 mask 255.0.0.0 10.55.11.253echo add 110.0.0.0 mask 255.0.0.0 10.55.11.253route add 110.0.0.0 mask 255.0.0.0 10.55.11.253echo ----------------------------------echo Press any key to leftecho ----------------------------------pauseecho Bye!exit
  • echo off 是將這個 把bat位置和指令暴露出來的設定 取消
  • echo on 則是把這個設定開啟
  • CLS : Clears the video display screen, setting the cursor in the upper left-hand corner.
  • pause 是用來暫停程式,不然沒指令後程式會自我關閉 (PAUSE : Pauses the running of a batch file and displays the message “Press any key to continue …” on the screen. If the optional message is included, it will be displayed first. Use pause to optionally terminate the batch file with at a safe place. The optional message is not displayed when echo is OFF, so the message must be echoed on the preceding line.)

更多batch關鍵字查詢

2014/09/24

Android 無法辨識 USB 裝置 (adb失效, 也偵測不到android手機或平板)

如果你的電腦 Windows或Linux 無法辨識Android USB裝置
也就是 adb失效, 而且偵測不到android手機或平板

 
(引用自Android developer)

USB Vendor IDs

This table provides a reference to the vendor IDs needed in order to add USB device support.

CompanyUSB Vendor ID
Acer0502
ASUS0b05
Dell413c
Foxconn0489
Fujitsu04c5
Fujitsu Toshiba04c5
Garmin-Asus091e
Google18d1
Haier201E
Hisense109b
HTC0bb4
Huawei12d1
Intel8087
K-Touch24e3
KT Tech2116
Kyocera0482
Lenovo17ef
LG1004
Motorola22b8
MTK0e8d
NEC0409
Nook2080
Nvidia0955
OTGV2257
Pantech10a9
Pegatron1d4d
Philips0471
PMC-Sierra04da
Qualcomm05c6
SK Telesys1f53
Samsung04e8
Sharp04dd
Sony054c
Sony Ericsson0fce
Sony Mobile Communications0fce
Teleepoch2340
Toshiba0930
ZTE19d2

可能是因為你的裝置VID並不在Google Vendor群裡面,
那就來手動將VID加入你的電腦裡面吧

Windows:

1. 先找出VID (Windows可以看裝置管理員裡,該裝置的硬體識別碼)
2. 建立目錄 C:\Users\YOUR_NAME\.android
3. 進入目錄後建立文字檔 adb_usb.ini 內容直接填寫Android裝置的VID (ex. 0x5566)

Linux:

1. 先找出VID (Linux可以看/sys/bus/usb/devices/ 以下的目錄, 可以找出新出現的目錄, 再去看idVendor內容即為VID )
2. 建立目錄 /home/YOUR_NAME/.android
3. 進入目錄後建立文字檔 adb_usb.ini 內容直接填寫Android裝置的VID (ex. 0x5566)

參考:
1. 書劍長風: Android USB VID PID 及 ADB
2. phonesdevelopers: Android USB VID PID and ADB
3. developer.android: USB Vendor IDs

2014/09/23

轉錄介紹- 什麼是Android Wi-Fi Display(Miracast)

先說這篇是引用轉路文章 出處, 想要研究一下MiraCast

前言

2012年11月中旬,Google發布了Android 4.2。雖然它和Android 4.1同屬Jelly Bean系列,但卻添加了很多新的功能。其中,在顯示部分,Android 4.2在Project Butter基礎上再接再厲,新增了對Wi-Fi Display功能的支持。由此也導致整個顯示架構發生了較大的變化。

本文首先介紹Wi-Fi Display的背景知識,然後再結合代碼對Android 4.2中Wi-Fi Display的實現進行介紹。

背景知識介紹

Wi-Fi Display經常和Miracast聯繫在一起。實際上,Miracast是Wi-Fi聯盟(Wi-Fi Alliance)對支持Wi-Fi Display功能的設備的認證名稱。通過Miracast認證的設備將在最大程度內保持對Wi-Fi Display功能的支持和兼容。由此可知,Miracast考察的就是Wi-Fi Display(本文後續將不再區分Miracast和Wi-Fi Display)。而Wi-Fi Display的核心功能就是讓設備之間通過Wi-Fi無線網路來分享視音頻數據。以一個簡單的應用場景為例:有了Wi-Fi Display后,手機和電視機之間可以直接藉助Wi-Fi,而無需硬連線(如HDMI)就可將手機中的視頻投遞到TV上去顯示[①]。以目前智能設備的發展趨勢來看,Wi-Fi Display極有可能在較短時間內幫助我們真正實現多屏互動。

從技術角度來說,Wi-Fi Display並非另起爐灶,而是充分利用了現有的Wi-Fi技術。圖1所示為Wi-Fi Display中使用的其他Wi-Fi技術項。



圖1 Miracast的支撐體系結構

  • – Wi-Fi Direct,也就是Wi-Fi P2P。它支持在沒有AP(Access Point)的情況下,兩個Wi-Fi設備直連並通信。
  • – Wi-Fi Protected Setup:用於幫助用戶自動配置Wi-Fi網路、添加Wi-Fi設備等。
  • – 11n/WMM/WPA2:其中,11n就是802.11n協議,它將11a和11g提供的Wi-Fi傳輸速率從56Mbps提升到300甚至600Mbps。WMM是Wi-Fi Multimedia的縮寫,是一種針對實時視音頻數據的QoS服務。而WPA2意為Wi-Fi Protected Acess第二版,主要用來給傳輸的數據進行加密保護。

上述的Wi-Fi技術中,絕大部分功能由硬體廠商實現。而在Android中,對Miracast來說最重要的是兩個基礎技術:

  • Wi-Fi Direct:該功能由Android中的WifiP2pService來管理和控制。
  • Wi-Fi Multimedia:為了支持Miracast,Android 4.2對MultiMedia系統也進行了修改。

下邊我們對Miracast幾個重要知識點進行介紹,首先是拓撲結構和視音頻格式方面的內容。

Miracast一個重要功能就是支持Wi-Fi Direct。但它也考慮了無線網路環境中存在AP設備的情況下,設備之間的互聯問題。讀者可參考如圖2所示的四種拓撲結構。



圖2 Miracast的四種拓撲結構

圖2所示內容比較簡單,此處就不再詳述。另外,在Wi-Fi Display規範中,還存在著Source將Video和Audio內容分別傳送給不同Render Device的情況。感興趣的讀者可參考Wi-Fi Display技術規範。

另外,Miracast對所支持的視音頻格式也進行了規定,如表1所示。

表1  Miracast 視音頻格式支持

解析度17種 CEA格式,解析度從640*480到1920*1080,幀率從24到6029種VESA格式,解析度從800*600到1920*1200,幀率從30到6012種手持設備格式,解析度從640*360到960*540,幀率從30到60
視頻H.264高清
音頻必選:LPCM 16bits,48kHz採樣率,雙聲道可選:LPCM 16bits,44.1kHz採樣率,雙聲道Advanced Audio coding

Dolby Advanced Codec 3

最後,我們簡單介紹一下Miracast的大體工作流程。Miracast以session為單位來管理兩個設備之間的交互的工作,主要步驟包括(按順序):

  • Device Discovery:通過Wi-Fi P2P來查找附近的支持Wi-Fi P2P的設備。
  • Device Selection:當設備A發現設備B后,A設備需要提示用戶。用戶可根據需要選擇是否和設備B配對。
  • Connection Setup:Source和Display設備之間通過Wi-Fi P2P建立連接。根據Wi-Fi Direct技術規範,這個步驟包括建立一個Group Owner和一個Client。此後,這兩個設備將建立一個TCP連接,同時一個用於RTSP協議的埠將被創建用於後續的Session管理和控制工作。
  • Capability Negotiation:在正式傳輸視音頻數據前,Source和Display設備需要交換一些Miracast參數信息,例如雙方所支持的視音頻格式等。二者協商成功后,才能繼續後面的流程。
  • Session Establishment and streaming:上一步工作完成後,Source和Display設備將建立一個Miracast Session。而後就可以開始傳輸視音頻數據。Source端的視音頻數據將經由MPEG2TS編碼后通過RTP協議傳給Display設備。-Display設備將解碼收到的數據,並最終顯示出來。
  • User Input back channel setup:這是一個可選步驟。主要用於在傳輸過程中處理用戶發起的一些控制操作。這些控制數據將通過TCP在Source和Display設備之間傳遞。
  • Payload Control:傳輸過程中,設備可根據無線信號的強弱,甚至設備的電量狀況來動態調整傳輸數據和格式。可調整的內容包括壓縮率,視音頻格式,解析度等內容。
  • Session teardown:停止整個Session。

 

通過對上面背景知識的介紹,讀者可以發現:

  • Miracast本質就是一個基於Wi-Fi的網路應用。這個應用包括服務端和客戶端。
  • 服務端和客戶端必須支持RTP/RTSP等網路協議和相應的編解碼技術。

二 Android 4.2 Miracast功能實現介紹

Miracast的Android實現涉及到系統的多個模塊,包括:

  • MediaPlayerService及相關模塊:原因很明顯,因為Miracast本身就牽扯到RTP/RTSP及相應的編解碼技術。
  • SurfaceFlinger及相關模塊:SurfaceFlinger的作用是將各層UI數據混屏並投遞到顯示設備中去顯示。現在,SurfaceFlinger將支持多個顯示設備。而支持Miracast的遠端設備也做為一個獨立的顯示設備存在於系統中。
  • WindowManagerService及相關模塊:WindowManagerService用於管理系統中各個UI層的位置和屬性。由於並非所有的UI層都會通過Miracast投遞到遠端設備上。例如手機中的視頻可投遞到遠端設備上去顯示,但假如在播放過程中,突然彈出一個密碼輸入框(可能是某個後台應用程序發起的),則這個密碼輸入框就不能投遞到遠端設備上去顯示。所以,WindowManagerService也需要修改以適應Miracast的需要。
  • DisplayManagerService及相關模塊:DisplayManagerService服務是Android 4.2新增的,用於管理系統中所有的Display設備。

由於篇幅原因,本文將重點關注SurfaceFlinger和DisplayManagerService以及Miracast的動態工作流程。

2.1 SurfaceFlinger對Miracast的支持

相比前面的版本,Android 4.2中SurfaceFlinger的最大變化就是增加了一個名為DisplayDevice的抽象層。相關結構如圖3所示:



圖3 SurfaceFlinger家族類圖
由圖3可知:

  • Surface系統定義了一個DisplayType的枚舉,其中有代表手機屏幕的DISPLAY_PRIMARY和代表HDMI等外接設備的DISPLAY_EXTERNAL。比較有意思的是,作為Wi-Fi Display,它的設備類型是DISPLAY_VIRTUAL。android/frameworks/native$ services/surfaceflinger/DisplayDevice.h
    class DisplayDevice : public LightRefBase{public:    // region in layer-stack space    mutable Region dirtyRegion;    // region in screen space    mutable Region swapRegion;    // region in screen space    Region undefinedRegion;    enum DisplayType {        DISPLAY_ID_INVALID = -1,        DISPLAY_PRIMARY     = HWC_DISPLAY_PRIMARY,        DISPLAY_EXTERNAL    = HWC_DISPLAY_EXTERNAL,        DISPLAY_VIRTUAL     = HWC_DISPLAY_VIRTUAL,        NUM_BUILTIN_DISPLAY_TYPES = HWC_NUM_PHYSICAL_DISPLAY_TYPES,    };

    再來看SurfaceFlinger類,其內部有一個名為mDisplays的變數,它保存了系統中當前所有的顯示設備(DisplayDevice)。另外,SurfaceFlinger通過mCurrentState和mDrawingState來控制顯示層的狀態。其中,mDrawingState用來控制當前正在繪製的顯示層的狀態,mCurrentState表示當前所有顯示層的狀態。有這兩種State顯示層的原因是不論是Miracast還是HDMI設備,其在系統中存在的時間是不確定的。例如用戶可以隨時選擇連接一個Miracast顯示設備。為了不破壞當前正在顯示的內容,這個新顯示設備的一些信息將保存到CurrentState中。等到SurfaceFlinger下次混屏前再集中處理。

  • mCurrentState和mDrawingState的類型都是SurfaceFlinger的內部類State。由圖3可知,State首先通過layerSortedByZ變數保存了一個按Z軸排序的顯示層數組(在Android中,顯示層的基類是LayerBase),另外還通過displays變數保存了每個顯示層對應的DisplayDeviceState。
    class SurfaceFlinger : public BnSurfaceComposer,                       private IBinder::DeathRecipient,                       private HWComposer::EventHandler{public:    ......    // access must be protected by mStateLock    mutable Mutex mStateLock;    State mCurrentState;    volatile int32_t mTransactionFlags;    Condition mTransactionCV;    bool mTransactionPending;    bool mAnimTransactionPending;    Vector< sp > mLayersPendingRemoval;    SortedVector< wp > mGraphicBufferProducerList;    ...    // Can only accessed from the main thread, these members    // don't need synchronization    State mDrawingState;    bool mVisibleRegionsDirty;    bool mHwWorkListDirty;    bool mAnimCompositionPending;    // this may only be written from the main thread with mStateLock held    // it may be read from other threads with mStateLock held    DefaultKeyedVector< wp, sp > mDisplays;	....};
  • DisplayDeviceState的作用是保存對應顯示層的DisplayDevice的屬性以及一個ISurfaceTexure介面。這個介面最終將傳遞給DisplayDevice。
  • DisplayDevice代表顯示設備,它有兩個重要的變數,一個是mFrameBufferSurface和mNativeWindow。mFrameBufferSurace是FrameBufferSurface類型,當顯示設備不屬於VIRTUAL類型的話,則該變數不為空。對於Miracast來說,顯示數據是通過網路傳遞給真正的顯示設備的,所有在Source端的SurfaceFlinger來說,就不存在FrameBuffer。故當設備為VIRTUAL時,其對應的mFrameBufferSurface就為空。而ANativeWindow是Android顯示系統的老員工了。該結構體在多媒體的視頻I/O、OpenGL ES等地方用得較多。而在普通的UI繪製中,ISurfaceTexture介面用得較多。不過早在Android 2.3,Google開發人員就通過函數指針將ANativeWindow的各項操作和ISurfaceTexture介面統一起來。

作為VIRTUAL的Miracast設備是如何通過DisplayDevice這一層抽象來加入到Surface系統中來的呢?下面這段代碼對理解DisplayDevice的抽象作用極為重要。如圖4所示。



圖4 SurfaceFlinger代碼片段
(以下是我看到的程式碼, 似乎已更改過了)

void SurfaceFlinger::init() {   ......    // initialize our non-virtual displays    for (size_t i=0 ; iisConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) {            // All non-virtual displays are currently considered secure.            bool isSecure = true;            createBuiltinDisplayLocked(type);            wp token = mBuiltinDisplays[i];            sp bq = new BufferQueue(new GraphicBufferAlloc());            sp fbs = new FramebufferSurface(*mHwc, i, bq);            sp hw = new DisplayDevice(this,                    type, allocateHwcDisplayId(type), isSecure, token,                    fbs, bq,                    mEGLConfig);            if (i > DisplayDevice::DISPLAY_PRIMARY) {                // FIXME: currently we don't get blank/unblank requests                // for displays other than the main display, so we always                // assume a connected display is unblanked.                ALOGD("marking display %d as acquired/unblanked", i);                hw->acquireScreen();            }            mDisplays.add(token, hw);        }    } ...}

由圖4代碼可知:

  • 對於非Virtual設備,DisplayDevice的FrameBufferSurface不為空。而且SurfaceTextureClient的構造參數來自於FrameBufferSurface的getBufferQueue函數。
  • 如果是Virtual設備,SurfaceTextureClient直接使用了State信息中攜帶的surface變數。

憑著上面這兩點不同,我們可以推測出如圖5所示的DisplayDevice的作用



圖5 DisplayDevice的隔離示意圖
由圖5可知,SurfaceFlinger將遍歷系統中所有的DisplayDevice來完成各自的混屏工作。
最後再來看一下SurfaceFlinger中混屏操作的實現,代碼如圖6所示:



圖6 SurfaceFilnger的混屏操作

SurfaceFlinger.cpp

void SurfaceFlinger::doComposition() {    ATRACE_CALL();    const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {        const sp& hw(mDisplays[dpy]);        if (hw->canDraw()) {            // transform the dirty region into this screen's coordinate space            const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));            // repaint the framebuffer (if needed)            doDisplayComposition(hw, dirtyRegion);            hw->dirtyRegion.clear();            hw->flip(hw->swapRegion);            hw->swapRegion.clear();        }        // inform the h/w that we're done compositing        hw->compositionComplete();    }    postFramebuffer();}

2.2 Framework對Miracast的支持

為了徹底解決多顯示設備的問題,Android 4.2乾脆在Framework中新增了一個名為DisplayManagerService的服務,用來統一管理系統中的顯示設備。
DisplayManagerService和系統其它幾個服務都有交互。整體結構如圖7所示。

android/frameworks/base/services/java/com/android/server/display/DisplayManagerService.java



圖7 DisplayManagerService及相關類圖

由圖7可知:

  • DisplayManagerService主要實現了IDisplayManager介面。這個介面的大部分函數都和Wi-Fi Display操作相關。
  • 另外,DisplayManagerService和WindowManagerService交互緊密。因為WindowManagerService管理系統所有UI顯示,包括屬性,Z軸位置等等。而且,WindowManagerService是系統內部和SurfaceFlinger交互的重要通道。
  • DisplayManagerService通過mDisplayAdapters來和DisplayDevice交互。每一個DisplayDevice都對應有一個DisplayAdapter。
  • 系統定義了四種DisplayAdapter。HeadlessDisplayAdapter和OverlayDisplayAdapter針對的都是Fake設備。其中OverlayDisplay用於幫助開發者模擬多屏幕之用。LocalDisplayAdapter代表主屏幕,而WifiDisplayAdapter代表Wi-Fi Display。

2.3 Android中Miracast動態工作流程介紹

當用戶從Settings程序中選擇開啟Miracast並找到匹配的Device後[③],系統將通過WifiDisplayController的requestConnect函數向匹配設備發起連接。代碼如圖8所示:



圖8 requestConnect函數實現

圖8中,最終將調用connect函數去連接指定的設備。 connect函數比較中,其中最重要的是updateConnection函數,我們抽取其中部分代碼來看,如圖9所示:



圖9 updateConnection函數片段

在圖8所示的代碼中,系統創建了一個RemoteDisplay,並在這個Display上監聽(listen)。從註釋中可知,該RemoteDisplay就是和遠端Device交互的RTP/RTSP通道。而且,一旦有遠端Device連接上,還會通過onDisplayConnected返回一個Sur​​face對象。
根據前面對SurfaceFlinger的介紹,讀者可以猜測出Miracast的重頭好戲就在RemoteDisplay以及它返回的這個Surface上了。
確實如此,RemoteDisplay將調用MediaPlayerService的listenForRemoteDisplay函數,最終會得到一個Native的RemoteDisplay對象。相關類圖如圖10所示。



圖10 RemoteDisplay類圖

由圖10可知,RemoteDisplay有三個重要成員變量:
mLooper,指向一個ALooper對象。這表明RemoteDisplay是一個基於消息派發和處理的系統。
mNetSession指向一個ANetWorkSession對象。從它的API來看,ANetworkSession提供大部分的網絡操作。
mSource指向一個WifiDisplaySource對象。它從AHandler派生,故它就是mLooper中消息的處理者。注意,圖中的M1、M3、M5等都是Wi-Fi Display技術規範中指定的消息名。
RemoteDisplay構造函數中,WifiDisplaySource的start函數將被調用。如此,一個類型為kWhatStart的消息被加到消息隊列中。該消息最終被WifiDisplaySource處理,結果是一個RTSPServer被創建。代碼如圖11所示:



圖11 kWhatStart消息的處理結果

以後,客戶端發送的數據都將通過類型為kWhatRTSPNotify的消息加入到系統中來。而這個消息的處理核心在onReceiveClientData函數中,它囊括了設備之間網絡交互的所有細節。其核心代碼如圖12所示:



圖12 onReceiveClientData核心代碼示意

圖12的內容較多,建議讀者根據需要自行研究。
根據前面的背景知識介紹,設備之間的交互將由Session來管理。在代碼中,Session的概念由WifiSource的內部類PlaybackSession來表示。先來看和其相關的類圖結構,如圖13所示:



圖13 PlaybackSession及相關類圖

由圖13可知:
 PlaybackSession及其內部類Track都從AHandler派生。故它們的工作也依賴於消息循環和處理。 Track代表視頻流或音頻流。
Track內部通過mMediaPull變量指向一個MediaPull對象。而MediaPull對象則保存了一個MediaSource對象。在PlaybackSession中,此MediaSource的真正類型為SurfaceMediaSource。它表明該Media的源來自Surface。
 BufferQueue從ISurfaceTexure中派生,根據前面對SurfaceFlinger的介紹,它就是SurfaceFlinger代碼示例中代表虛擬設備的State的surface變量。
當雙方設備準備就緒後,MediaPull會通過kWhatPull消息處理不斷調用MediaSource的read函數。在SurfaceMediaSource實現的read函數中,來自SurfaceFlinger的混屏後的數據經由BufferQueue傳遞到MediaPull中。代碼如圖14所示:



圖14 MediaPull和SurfaceMediaSource的代碼示意

從圖13可知:
左圖中,MediaPull通過kWhatPull消息不斷調用MediaSource的read函數。
右圖中,SurfaceMediaSource的read函數由通過mBufferQueue來讀取數據。
那麼mBufferQueue的數據來自什麼地方呢?對,正是來自圖4的SurfaceFlinger。
當然,PlaybackSession拿到這些數據後還需要做編碼,然後才能發送給遠端設備。由於篇幅關係,本文就不再討論這些問題了。

三. 總結

本文對Miracast的背景知識以及Android系統中Miracast的實現進行了一番簡單介紹。從筆者個人角度來看,有以下幾個點值得感興趣的讀者註意:
一定要結合Wi-Fi的相關協議去理解Miracast。重點關注的協議包括Wi-Fi P2p和WMM。

 Android Miracast的實現中,需要重點理解SurfaceFlinger和RemoteDisplay模塊。這部分的實現不僅代碼量大,而且類之間,以及線程之間關係複雜。
其他需要注意的點就是DisplayManagerService及相關模塊。這部分內容在SDK中有相關API。應用開發者應關注這些新API是否能幫助自己開發出更有新意的應用程序。
另外,Android的進化速度非常快,尤其在幾個重要的功能點上。作者在此也希望國內的手機廠商或那些感興趣的移動互聯網廠商能真正投入力量做一些更有深度和價值的研發工作。

2014/09/18

卡關筆記 base_rules.mk:72: *** user tag detected on module.. 如何把 module正確編譯且產生出來

首先發生了error
編譯到一半就有訊息跳出並停止編譯
它跟我說我用了 user tag 所以STOP…

build/core/base_rules.mk:66: * build/core/base_rules.mk:67: * Module is attempting to use the 'user' tag.  This build/core/base_rules.mk:68: * used to cause the module to be installed automatically. build/core/base_rules.mk:69: * Now, the module must be listed in the PRODUCT_PACKAGES build/core/base_rules.mk:70: * section of a product makefile to have it installed. build/core/base_rules.mk:71: * build/core/base_rules.mk:72: *** user tag detected on module..  Stop. 

去看了一看我的 module’s Android.mk
如下

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := test_wifiLOCAL_SRC_FILES := test_wifi.shLOCAL_MODULE_SUFFIX := .shLOCAL_MODULE_CLASS := ETCLOCAL_MODULE_TAGS := userinclude $(BUILD_PREBUILT)

關鍵在 LOCAL_MODULE_TAGS

eng:
我還沒改之前為eng, 而eng表示系統會自動搬入 out/product/xxx/xxx (看你怎麼寫, 像此例是LOCAL_MODULE_CLASS := ETC 所以是system/etc)

user:
如果是 LOCAL_MODULE_TAGS := user 就上面的error message
可能有些地方不能隨意定義成user吧… 害我一開始還跟著error message去試著將module name加入 PRODUCT_PACKAGES定義裡
也沒用, 還是fail

optional:
可以改成 LOCAL_MODULE_TAGS := optional , 但必須說明是否搬入out目錄裡
怎麼說明呢?
去把該module name (此例為test_wifi)加入 PRODUCT_PACKAGES定義裡
可以寫在
1) /android/build/target/product/generic.mk 或附近的mk檔
2) 又或者, 其他可以定義 PRODUCT_PACKAGES += xxxxx 的makedile裡 (.mk檔) 必須看你的codebase什麼地方有PRODUCT_PACKAGES += xxxxx 就接著寫在下面吧

我後來處理的寫法

diff給你看

@@ -4,5 +4,5 @@ include $(CLEAR_VARS) LOCAL_MODULE := test_wifi LOCAL_SRC_FILES := test_wifi.sh LOCAL_MODULE_SUFFIX := .sh LOCAL_MODULE_CLASS := ETC-LOCAL_MODULE_TAGS := eng+LOCAL_MODULE_TAGS := eng optional include $(BUILD_PREBUILT)

PRODUCT_PACKAGES宣告

 PRODUCT_PACKAGES += TE_WGA+PRODUCT_PACKAGES += test_wifi

2014/09/15

測試802.11a, 802.11b, 802.11g, 802.11n, 802.11ac的研讀整理

工作上必須去量測DUT的Wifi訊號
而量測的工具是LitePoint IQ2010
看之前可以先讀這篇: 網路架構大概論6-看懂無線網路 802.11 b/g/n/ac 演進歷史 熟習WiFi故事前後關係

這是IEEE所定出來的規範,無線技術從802.11開始發展,再延伸出802.11b/g/n是縮寫各自都是代表不同的規範,但都是建構在802.11下開發出來的無線技術所以802.11b/802.11g/802.11n,載波頻段在2.4GHz,b/g/n技術稍微不同所以速率也是有所提升,以最高速度來說802.11n > 802.11g > 802.11b。

802.11ac是802.11a的進階版(增加頻寬,增加調變能力,etc),所以才叫做802.11ac而不叫做802.11c,而802.11a與802.11ac採使用的主要頻段是5GHz,其中802.11n也有5GHz的技術。802.11ac是目前base on 802.11延伸出的無線技術中,傳輸速度最快的。

比較夯的Protocol

802.11a (5GHz)
802.11b
802.11g
802.11n
802.11ac (關於測試的說明)

Modulation(調變)

  • OFDM- 802.11a, 802.11g, 802.11n, 802.11ac
    Orthogonal frequency-division multiplexing 正交分頻多工, OFDM 是一種資料編碼的技術,利用在不同頻段同時傳送資料以增加傳輸速率,其目的除了可以善加利用寶貴的頻譜外,更可以克服頻率選擇性殘衰頻道 (frequency selective fading channel)。OFDM符號的調變與解調是交由BPSK、QPSK、16-QAM或64-QAM等四種鍵控調變技術執行,並在搭配不同通道編碼率的情況下,提供八種不同的資料傳輸率
  • DSSS- Legacy, 802.11b, 802.11g
    direct-sequence spread spectrum 直接序列展頻, 在傳送端,直接用高碼率的展頻碼序列去擴充功能訊號的頻譜,在接收端,用相同的展頻碼序列將訊號解擴,把展寬的訊號還原到原始狀態。
  • FHSS- Legacy
    Frequency-hopping spread spectrum 跳頻展頻, 是展頻技術的一種;經由載波快速在不同頻率中切換,並在接收與發射端使用一種偽隨機(PseudoRandom)的過程。

頻寬(MHz)
頻寬有兩個涵義
一種是指頻率範圍(width of a frequency band) ,以Hz (Hertz)為單位 (也就是此處用法)
另一種則是我們熟悉的通訊線路的資料速率(data rate),可用bits per second來表示
另一個和頻寬有關的觀念是所謂的傳輸效率(throughput) ,代表實測的頻寬

  • HT20- 802.11a, 802.11b, 802.11g, 802.11n HT(High Throughput)20MHz
  • HT40- 802.11n, 802.11ac HT(High Throughput)40MHz
  • HT80- 802.11ac HT(High Throughput)80MHz
  • HT160- 802.11ac HT(High Throughput)160MHz

專有名詞

還滿多可以從這份文件Practical Manufacturing Testing of 802.11 OFDM Wireless Devices找到的

  • Constellation Diagram: 星座圖
    The Constellation Diagram is a representation of a signal modulated by a digital modulation scheme. The plots in Figure 6 show
    typical constellations for an OFDM signal. The green constellation points represent the information from the pilot subcarriers; the
    red constellation points, the data on the subcarriers. (From litepoint)
  • EVM :誤差向量幅度(Error Vector Magnitude)
    可以檢測出數位調變訊號的品質,並且找出射頻訊號失真的原因及可能發生失真的電路位置,包括:功率放大器的增益壓縮 (gain compression)、本地振盪貫穿 (LOfeedthrough)、IQ 增益不平衡 (gain imbalance)、載波頻率抵補 (carrier frequency offset)、相位雜訊(phase noise) 干擾及符號間干擾 (intersymbolinterference, ISI) 等,這是傳統射頻儀器或位元錯誤率 (bit error rate, BER) 量測儀器所無法測出的。
    針對調變過的訊號,EVM 將比較訊號預期與實際的相位/強度。如圖所示,將錯誤向量 |E| 除以強度向量 |V|,得出該值。
    (參考自:設定軟體定義架構的 WLAN 測試系統)
  • MCS:
    調變標準指標 Modulation and Coding Scheme, 透過index查表知道調變內容
    這裡有說明怎麼看MCS表,

    • MCS index 就是指速度的指標. 比方說我支持到 MCS7, 他支援到 MCS15 之類的
    • Spatial Stream 是指空間流或是空間串流, 要明白空間串流就要先明白空間分集. 假如在訊號的發送端有多個天線, 而每個天線的訊號都會透過不同的路徑到達接收端的天線, 這樣就構成了空間的分割或是分集. 如果天線不夠多支, 也就無法做到分集. 11n 的規範最多就是支援 4 支天線.
    • Modulation type 就是通訊原理裡面講的調變方法.
    • Coding rate N/M 是指傳送 M bit 時, 裡面有 N bit 是 data, 當然 M – N 就是 redundant 了. Redundant 不是沒有用, 反而可以防錯或是校正錯誤.
    • 20 MHz channel 或 40 MHz 是通道的頻寬
    • GI 的單位是時間, 所以可以猜到 I 表示 Interval. 對, GI 就是 Guard Interval. 在兩個 OFDM 的 symbol 之間的傳送間隔即為 GI. GI 愈短, 則傳輸速率愈高.
    • 在 4 根天線的狀況下, 距離不要太遠 (coding rate 高) 的話, 11n 可以達到 600 Mbps. 而一開始講到的 MCS7 和 MCS15, 其他的條件都是一樣的, 只差在空間串流的數目. 這點可以從天線的多寡很快判斷出來, 沒有兩根天線是不可能做 MCS15 的.

    http://mcsindex.com/

  • Frequency Error:
    就是量測出來的載波頻率與預期的頻率差異(A Frequency Error measures the difference (misalignment) between the carrier frequency generated by the reference oscillators at the transmitter and the expected carrier frequency.)
  • Spectrum Mask(Spectral Mask): 頻譜遮罩
    就是每個channel的訊號power強度分布圖, 不要超出範圍影響別的訊號 (A Spectral Mask describes the distribution of signal power across each channel.)
  • Spectral Flatness: 頻譜平坦性
    defined as the geometric mean(幾何平均數) of the power spectrum divided by the arithmetic mean(算術平均數) of the power spectrum.
  • Transmit Center Frequency Leakage: 傳遞中心頻率缺漏
    DC offset can affect certain transmitter implementations in the up-converter path, and usually causes carrier leakage. Such leakage manifests itself in a receiver as energy in the transmit center frequency, hence the name Transmit Center Frequency Leakage.

2014/09/11

shell script錯誤: Bad substitution

通常會造成 Bad substitution 錯誤
大部分是因為第一行的定義沒寫好.當然也可能是語法錯誤

我將第一行改寫為預設bash如下, 即可解決

#!/bin/bash

根據鳥哥說明:
可以檢查一下 /etc/shells 這個檔案,至少就有底下這幾個可以用的 shells:

/bin/sh (已經被 /bin/bash 所取代)/bin/bash (就是 Linux 預設的 shell)/bin/ksh (Kornshell 由 AT&T Bell lab. 發展出來的,相容於 bash)/bin/tcsh (整合 C Shell ,提供更多的功能)/bin/csh (已經被 /bin/tcsh 所取代)/bin/zsh (基於 ksh 發展出來的,功能更強大的 shell)

這個問題有點類似之前寫的一篇文章, 也說明了一下dash與bash的設定
UBUNTU- 執行SHELL SCRIPT 為什麼常發生 UNEXPECTED OPERATOR

2014/09/10

如何快速更新DNS對應的IP Address

有時候domain name server對應到的 IP address更動,

要等好長一段時間才會自動生效,

其實只要幾個步驟就可以很快完成新IP位址與網域的對應

Step1: 更新OpenDNS CacheCheck

前往 http://cachecheck.opendns.com/ 刷新
OpenDNS的有巨大的緩存,這是一個原因,OpenDNS的讓您的互聯網體驗更快。
隨著CacheCheck,你可以查閱一下OpenDNS的客戶看到,當他們請求域。
如果有什麼東西不對勁,你可以刷新的OpenDNS的緩存域。

Step2: 清除自己系統DNS快取

如果是使用 Windows 作業系統,請以管理員權限進入「附屬應用程式」的「命令提示字元」,或是直接在執行列輸入「cmd」,然後鍵入以下指令:
ipconfig /flushdns

如果你是使用 Mac OS X 的話,請進入終端機視窗,然後鍵入以下指令:
lookupd -flushcache (Mac OS Tiger 或更早前的版本)
dscacheutil -flushcache (Mac OS X 10.5 Leopard 以後的版本)

如果你是 Linux 的使用者,必須輸入以下指令重新啟動 nscd :
/etc/rc.d/init.d/nscd restart

如此一來就能手動清除系統的DNS快取資料,並重新從OpenDNS獲得新的紀錄,對於時常要搬移網站,或是設定對應新IP的使用者來說,會是個比較省時省力的作法,也不用為了等待DNS生效而耗費數個小時。
但順帶一提,這麼做並不能更新所有使用者的DNS記錄,其他人還是必須在變更生效後才能正確瀏覽你的網站。

2014/09/05

Android手機的Linux發生Kernel Panic ..

在作monkey測試的時候, 發生kernel panic
但是發生機率很低, 加上目前硬體還不穩定, 所以努力複現中…

關於Kernel Panic 稍微google了一下
第一. 可以先了解什麼是Linux kernel panic (參考1)
第二. 怎麼看LOG (參考2)

以下就是發生kernel panic的LOG,
隨意分析與註解一下

[38373.777729] Unable to handle kernel NULL pointer dereference at virtual address 00000000[38373.784640] Unable to handle kernel NULL pointer dereference at virtual address 00000224這個pgd is short for "page global directory", the kernel's name for the top level of a page table.[38373.784647] pgd = da350000[38373.784651] [00000224] *pgd=00000000下方數字5表示Oops的錯誤碼(詳情請trace code),#1表示这个错误发生一次.[38373.784661] Internal error: Oops: 5 [#1] PREEMPT SMP ARM[38373.784667] Modules linked in: wlan(O) [last unloaded: wlan][38373.784680] CPU: 0    Tainted: G        W  O  (3.4.0-g6e71111 #1)PC 或 EIP 會去指出發生錯誤的地方, 此處是PC指出所以是在contextidr_notifier的offset為0x10的位址發生了錯誤,此時用objdump -d,將該模組反組譯,觀察該位址應該就可以猜出來是怎麼一回事。[38373.784695] PC is at contextidr_notifier+0x10/0x40[38373.784704] LR is at notifier_call_chain+0x38/0x68[38373.784712] pc : []    lr : []    psr: 60000013[38373.784715] sp : cf6d7d08  ip : c0f29fd8  fp : cf6d7df4[38373.784720] r10: e9d8bdc0  r9 : ea0d8000  r8 : c0f2836c[38373.784727] r7 : e9402000  r6 : 00000002  r5 : 00000000  r4 : ffffffff[38373.784733] r3 : 00000000  r2 : e9402000  r1 : 00000002  r0 : c0f29fd8[38373.784741] Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user[38373.784747] Control: 10c5787d  Table: 2a0dc06a  DAC: 00000015[38373.784753] [38373.784755] PC: 0xc0114e78:[38373.784759] 4e78  ee0d4f30 f57ff06f e8bd8010 e92d4070 e2805e16 e1a04000 e1a00005 e1a06001[38373.784773] 4e98  eb202eea e59f3040 e1a01000 e1a00005 e593200c e594315c e0223003 e1b03423[38373.784788] 4eb8  13a03000 1584615c 15843158 eb202fd6 e1a0200d e2841f56 e3c23d7f e3c3303f[38373.784803] 4ed8  e5930014 e8bd4070 ea09ec62 c0f29fd8 e3510002 e92d4010 1a00000a e592300c[38373.784818] 4ef8  e5930224 e10f4000 f10c0080 ee1d3f30 e6ef3073 e1830400 ebffffd3 e121f004[38373.784832] 4f18  e3a00001 e8bd8010 e3a00000 e8bd8010 e92d4008 ee1d0f30 e3c000ff ebffffca[38373.784847] 4f38  f57ff04f e3a03000 ee083f13 f57ff04f f57ff06f e59f2014 e5922000 e3120008[38373.784861] 4f58  08bd8008 ee073f11 f57ff04f e8bd8008 c0f1e4d8 e92d4038 e1a0200d e3c23d7f[38373.784877] [38373.784878] LR: 0xc0922ea0:[38373.784881] 2ea0  e3c13dff e7951180 e3c3303f e2833103 e0832002 e7831180 e5943004 e5823004[38373.784896] 2ec0  ee072f3a f57ff04f ea000003 e1a00003 e1a01006 e1a0200c ebdfbc4d e3a00000[38373.784910] 2ee0  e8bd80f8 c0f531c8 e92d41f0 e1a06001 e590c000 e1a07002 e1a04003 e59d5018[38373.784925] 2f00  e3a00000 ea00000d e59c3000 e1a0000c e1a01006 e1a02007 e59c8004 e12fff33[38373.784939] 2f20  e3550000 15953000 12833001 15853000 e3100902 18bd81f0 e2444001 e1a0c008[38373.784953] 2f40  e3540000 135c0000 1affffee e8bd81f0 e92d40f7 e1a04003 e1a07000 e1a06001[38373.784967] 2f60  e1a05002 ebe368ed e59d3020 e1a01006 e1a02005 e2870004 e58d3000 e1a03004[38373.784982] 2f80  ebffffd8 e1a04000 ebe36ce1 e1a00004 e8bd80fe e3a03000 e92d4007 e58d3000[38373.784997] [38373.784998] SP: 0xcf6d7c88:[38373.785002] 7c88  c30e3570 c0f49cc0 38a5f3a8 c0191900 c0f2b1e8 c0114ef8 60000013 ffffffff[38373.785016] 7ca8  cf6d7cf4 c0f2836c ea0d8000 e9d8bdc0 cf6d7df4 c0921418 c0f29fd8 00000002[38373.785031] 7cc8  e9402000 00000000 ffffffff 00000000 00000002 e9402000 c0f2836c ea0d8000[38373.785045] 7ce8  e9d8bdc0 cf6d7df4 c0f29fd8 cf6d7d08 c0922f20 c0114ef8 60000013 ffffffff[38373.785059] 7d08  ffffffff c0922f20 ffffffff e9402000 00000002 c10f4824 e99dddc0 c0922f84[38373.785073] 7d28  00000000 00000002 e9402000 e940201c e8148e40 cf6d6000 00000000 c0922fa8[38373.785087] 7d48  00000000 00000002 e9402000 c0921858 00000000 c0f1fdc0 c0f12c70 c0f12c70[38373.785102] 7d68  1877c34f 00000000 c0f158c0 c091e47c c0f124d0 c0f158c0 97cd0c7b 000022e6[38373.785117] [38373.785119] IP: 0xc0f29f58:[38373.785122] 9f58  00000000 00000043 00000001 00000000 00000000 00000043 00000001 00010412[38373.785136] 9f78  00000000 00000000 00000000 0001941e 00000000 00000000 00000000 0001141e[38373.785150] 9f98  00000000 00000000 00000000 0001940e 00000000 0000045f 00000001 00000000[38373.785164] 9fb8  00000000 000007d3 00000041 00010442 00000002 c01147b8 c0f2ae34 00000000[38373.785178] 9fd8  c0114ee8 c0f2836c 00000000 00008c7b c0c1155f 00000000 00000000 00000000[38373.785192] 9ff8  c01152c0 00000000 c01157d8 00000000 c0115748 c01156a0 c0115868 c01152e0[38373.785206] a018  c01154d0 00000000 c011535c 00000000 00000000 00000000 00000000 00000000[38373.785219] a038  00000000 00000000 00000000 00000000 c0f28758 c0f41948 c01153e0 c0115afc[38373.785234] [38373.785236] FP: 0xcf6d7d74:[38373.785239] 7d74  c091e47c c0f124d0 c0f158c0 97cd0c7b 000022e6 00000001 c30e68c0 cf6d7de4[38373.785253] 7d94  c01ca574 00000000 00000000 00000005 97cc89aa 000022e6 e9d8bdc0 c30e68c0[38373.785267] 7db4  00000005 c30e68c0 c0f158c0 cf6d7de4 c01c2fd0 00000100 e9d8bdc0 00000000[38373.785281] 7dd4  c118c040 003a1c79 c118c040 0000006e 000003e8 eb3aaad0 cf6d7eb4 cf6d6000[38373.785295] 7df4  c091e47c c30e68c0 a0000013 c118c930 c118c930 003a1c79 c118c040 c01a5574[38373.785310] 7e14  e8148e40 ffffffff ffffffff 00000000 00000000 00000000 00000000 00000000[38373.785324] 7e34  271ae91c cf6d7e5c e749cc00 00000000 00000001 e749ccb8 c06f5244 eb3aaa00[38373.785338] 7e54  c0714558 e749cc00 00000000 e8148e40 c01c5e54 e749ccbc e749ccbc 0008a390[38373.785353] [38373.785355] R0: 0xc0f29f58:[38373.785359] 9f58  00000000 00000043 00000001 00000000 00000000 00000043 00000001 00010412[38373.785373] 9f78  00000000 00000000 00000000 0001941e 00000000 00000000 00000000 0001141e[38373.785386] 9f98  00000000 00000000 00000000 0001940e 00000000 0000045f 00000001 00000000[38373.785400] 9fb8  00000000 000007d3 00000041 00010442 00000002 c01147b8 c0f2ae34 00000000[38373.785414] 9fd8  c0114ee8 c0f2836c 00000000 00008c7b c0c1155f 00000000 00000000 00000000[38373.785428] 9ff8  c01152c0 00000000 c01157d8 00000000 c0115748 c01156a0 c0115868 c01152e0[38373.785442] a018  c01154d0 00000000 c011535c 00000000 00000000 00000000 00000000 00000000[38373.785456] a038  00000000 00000000 00000000 00000000 c0f28758 c0f41948 c01153e0 c0115afc[38373.785471] [38373.785472] R2: 0xe9401f80:[38373.785475] 1f80  0000c8c0 00000000 00000040 00000040 000aebea 2756ccf4 e9401f98 e9401f98[38373.785490] 1fa0  00100010 ffffffff 00000000 00000000 00000000 0000007f 00000000 0000001c[38373.785503] 1fc0  e9401fc0 e9401fc0 02a202a2 00000000 00000000 00000000 01140114 00010a69[38373.785517] 1fe0  0000bd4b 00000000 e9401ff0 e9401fec 0001f30a 00000004 00000000 00000000[38373.785531] 2000  00000008 005e925f 00000000 00000000 00000000 00000000 00000000 00000000[38373.785544] 2020  00000000 00000000 00000000 00000000 00000000 00000000 000000bd 00000000[38373.785558] 2040  00000004 00080080 00000000 00200020 e9402050 e9402050 e9402058 e9402058[38373.785572] 2060  00008000 00000000 00000000 02740274 e9402070 e9402070 00058180 00002715[38373.785587] [38373.785589] R7: 0xe9401f80:[38373.785592] 1f80  0000c8c0 00000000 00000040 00000040 000aebea 2756ccf4 e9401f98 e9401f98[38373.785606] 1fa0  00100010 ffffffff 00000000 00000000 00000000 0000007f 00000000 0000001c[38373.785620] 1fc0  e9401fc0 e9401fc0 02a202a2 00000000 00000000 00000000 01140114 00010a69[38373.785634] 1fe0  0000bd4b 00000000 e9401ff0 e9401fec 0001f30a 00000004 00000000 00000000[38373.785648] 2000  00000008 005e925f 00000000 00000000 00000000 00000000 00000000 00000000[38373.785661] 2020  00000000 00000000 00000000 00000000 00000000 00000000 000000bd 00000000[38373.785675] 2040  00000004 00080080 00000000 00200020 e9402050 e9402050 e9402058 e9402058[38373.785690] 2060  00008000 00000000 00000000 02740274 e9402070 e9402070 00058180 00002715[38373.785704] [38373.785706] R8: 0xc0f282ec:[38373.785709] 82ec  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38373.785723] 830c  00000000 00000000 636f6c00 6f646c61 6e69616d 00000000 00000000 00000000[38373.785737] 832c  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38373.785750] 834c  00000000 00000000 00000000 c0f4cd68 00008001 c0c0cfda 00000000 c01013e4[38373.785764] 836c  c01010fc 00000000 00000000 c0101048 00000000 00000000 000000ff 20000000[38373.785779] 838c  c0101a98 00000000 c0101a80 00000000 c0101a68 00000000 c01030cc 00000000[38373.785792] 83ac  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38373.785806] 83cc  c01025a4 00000001 c010259c 00000001 c0102590 00000001 c0102584 00000001[38373.785820] [38373.785822] R9: 0xea0d7f80:[38373.785825] 7f80  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38373.785839] 7fa0  00000000 00000000 00000000 00000000 00000000 00000000 2b9b9811 2b9b9c11[38373.785853] 7fc0  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38373.785866] 7fe0  00000000 00000000 00000000 00000000 00000000 00000000 2def6821 2def6c21[38373.785880] 8000  e869f738 ea1f5c24 00000000 c0112dbc c024760c b6f6c000 bf000000 00000000[38373.785895] 8020  b284b000 ea0dc000 0000000d 00000001 00000167 d199d199 00000000 a578a578[38373.785909] 8040  ea0d8040 ea0d8040 ea0d8048 ea0d8048 00000aaa 0000d3ac 00007f0d 00000000[38373.785923] 8060  00000000 00006ed7 00000d82 00000022 00005f04 00000000 00000047 b6f6b000[38373.785937] [38373.785939] R10: 0xe9d8bd40:[38373.785943] bd40  00000000 eb3d79c0 eb218448 e9d8c208 00000000 e9d8bd54 e9d8bd54 00000000[38373.785957] bd60  00000000 00000000 00000001 00000000 e9d8bd70 e9d8bd70 00000000 e9d8bd7c[38373.785971] bd80  e9d8bd7c 00000000 00000000 00000000 00000000 00000000 00000020 00000000[38373.785984] bda0  0000c350 0000c350 00000000 00000000 00000000 00000001 00000000 00000000[38373.785998] bdc0  00000000 e9402000 00000002 00000040 00000000 00000000 00000001 00000001[38373.786012] bde0  0000006f 0000006f 0000006f 00000000 c0a0af78 00000000 00001dc4 000899bc[38373.786026] be00  00000001 00000000 00000000 c30e6d8c c30e6d8c 00000001 97cd0c7b 000022e6[38373.786040] be20  342ca642 0000000e 15dabd8e 00002688 342ca642 0000000e 0000e830 00000000[38373.786057] Process FastMixer (pid: 21242, stack limit = 0xcf6d62f0)[38373.786063] Stack: (0xcf6d7d08 to 0xcf6d8000)[38373.786070] 7d00:                   ffffffff c0922f20 ffffffff e9402000 00000002 c10f4824[38373.786079] 7d20: e99dddc0 c0922f84 00000000 00000002 e9402000 e940201c e8148e40 cf6d6000[38373.786087] 7d40: 00000000 c0922fa8 00000000 00000002 e9402000 c0921858 00000000 c0f1fdc0[38373.786095] 7d60: c0f12c70 c0f12c70 1877c34f 00000000 c0f158c0 c091e47c c0f124d0 c0f158c0[38373.786103] 7d80: 97cd0c7b 000022e6 00000001 c30e68c0 cf6d7de4 c01ca574 00000000 00000000[38373.786111] 7da0: 00000005 97cc89aa 000022e6 e9d8bdc0 c30e68c0 00000005 c30e68c0 c0f158c0[38373.786119] 7dc0: cf6d7de4 c01c2fd0 00000100 e9d8bdc0 00000000 c118c040 003a1c79 c118c040[38373.786128] 7de0: 0000006e 000003e8 eb3aaad0 cf6d7eb4 cf6d6000 c091e47c c30e68c0 a0000013[38373.786136] 7e00: c118c930 c118c930 003a1c79 c118c040 c01a5574 e8148e40 ffffffff ffffffff[38373.786144] 7e20: 00000000 00000000 00000000 00000000 00000000 271ae91c cf6d7e5c e749cc00[38373.786152] 7e40: 00000000 00000001 e749ccb8 c06f5244 eb3aaa00 c0714558 e749cc00 00000000[38373.786160] 7e60: e8148e40 c01c5e54 e749ccbc e749ccbc 0008a390 e749cc00 eb3aaa00 00000000[38373.786168] 7e80: 000000f0 00000020 00000000 eb3aaad0 00000000 c06f6de4 eb3aaa00 60000193[38373.786176] 7ea0: ec3c0e40 c11dc388 b72316c8 00000000 b722662c 00000000 ec2a1260 00000003[38373.786184] 7ec0: eb3aaa00 00000000 400c4150 00000020 cf6d6000 b5839a4c ea241ce0 c06f6fb4[38373.786193] 7ee0: c06f5520 b72316c8 b5839a4c c06f35ec e752f0c0 00000000 b72316c8 000000f0[38373.786201] 7f00: 00000000 e752f0c0 00000020 400c4150 00000020 c026c644 ea53bb00 c026d184[38373.786209] 7f20: cf6d7f44 00000000 00000001 c034ab38 00000000 cf6d7f58 cf6d7f90 00000000[38373.786218] 7f40: 00000000 00000001 00000000 ebb1b190 ea53bb00 cf6d7f3c 00000008 b7252c28[38373.786226] 7f60: e752f0c0 00000000 e752f0c0 b5839a4c 400c4150 00000020 cf6d6000 00000000[38373.786235] 7f80: b722662c c026d220 00000020 00000001 b7252c28 000003c0 b7221160 00000036[38373.786243] 7fa0: c01062e4 c0106160 b7252c28 000003c0 00000020 400c4150 b5839a4c b5839a40[38373.786252] 7fc0: b7252c28 000003c0 b7221160 00000036 b72211c4 b587a298 b587a268 b722662c[38373.786260] 7fe0: 000003c0 b5839a30 b6f83f87 b6f776f8 800e0010 00000020 00000000 00000000開始Backtrace的地方,這是oops kernel panic log 的精華。它表示回溯信息,也告訴調試者在oops出錯之前,模塊調用了那些函數。當然,在本實例中,可以看到模塊調用了contextidr_notifier後就出錯了,顯然錯誤就在contextidr_notifier中了[38373.786278] [] (contextidr_notifier+0x10/0x40) from [] (notifier_call_chain+0x38/0x68)[38373.786292] [] (notifier_call_chain+0x38/0x68) from [] (__atomic_notifier_call_chain+0x34/0x44)[38373.786304] [] (__atomic_notifier_call_chain+0x34/0x44) from [] (atomic_notifier_call_chain+0x14/0x18)[38373.786317] [] (atomic_notifier_call_chain+0x14/0x18) from [] (__switch_to+0x34/0x5c)[38373.786327] Code: e3510002 e92d4010 1a00000a e592300c (e5930224) [38373.786386] ---[ end trace f3db8a93ae8449a4 ]---[38373.786393] panic: rere = 0x46544443[38373.786422] Kernel panic - not syncing: Fatal exception以下好像是直接繼續另一個panic ...[38374.899743] pgd = c0004000[38374.902434] [00000000] *pgd=00000000[38374.905999] Internal error: Oops: 5 [#2] PREEMPT SMP ARM[38374.911283] Modules linked in: wlan(O) [last unloaded: wlan][38374.916934] CPU: 3    Tainted: G      D W  O  (3.4.0-g6e71111 #1)[38374.923021] PC is at strcmp+0x8/0x3c[38374.926576] LR is at msm_pm_get_sleep_mode_value+0x40/0x70[38374.932048] pc : []    lr : []    psr: 20000093[38374.932062] sp : ec89be70  ip : c60f3fc0  fp : 00000000[38374.943493] r10: 00000000  r9 : c11693d8  r8 : c0f1f008[38374.948703] r7 : 00000001  r6 : c11093d8  r5 : 00b00160  r4 : 0016002c[38374.955211] r3 : 00000000  r2 : 00000000  r1 : 00000000  r0 : c11093d8[38374.961727] Flags: nzCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment kernel[38374.969103] Control: 10c5787d  Table: 29d8406a  DAC: 00000015[38374.974824] [38374.974830] PC: 0xc039890c:[38374.979074] 890c  c0a33072 e3a03000 e7d12003 e3520000 e7c02003 e2833001 1afffffa e12fff1e[38374.987236] 892c  e3a03000 ea000004 e5d1c000 e35c0000 e7c0c003 e2833001 12811001 e1530002[38374.995394] 894c  1afffff8 e12fff1e e1a0c000 e1a0200c e28cc001 e5d23000 e3530000 1afffffa[38375.003554] 896c  e7d1c003 e35c0000 e7c2c003 e2833001 1afffffa e12fff1e e3a03000 e7d02003[38375.011713] 898c  e7d1c003 e152000c 0a000002 2a000006 e3e00000 e12fff1e e3520000 e2833001[38375.019872] 89ac  1afffff5 e1a00002 e12fff1e e3a00001 e12fff1e e92d4010 e3a03000 ea000009[38375.028032] 89cc  e7d0c003 e7d14003 e15c0004 0a000002 2a000008 e3e00000 e8bd8010 e35c0000[38375.036192] 89ec  e2833001 0a000001 e1530002 1afffff3 e3a00000 e8bd8010 e3a00001 e8bd8010[38375.044358] [38375.044364] LR: 0xc017a91c:[38375.048605] a91c  e1a00006 e0823005 e5931004 eb087815 e3500000 028d3028 00835005 05150028[38375.056767] a93c  0a000003 e2844001 e3540005 1afffff1 e3e00015 e28dd028 e8bd8070 c0a07890[38375.064926] a95c  e92d4070 e1a06000 e59fe05c e24dd020 e3a04000 e1a0c00d e8be000f e8ac000f[38375.073084] a97c  e89e000f e88c000f e1a05184 e28d2000 e1a00006 e0823005 e5931004 eb0877f9[38375.081244] a99c  e3500000 028d3020 00835005 05150020 0a000003 e2844001 e3540004 1afffff1[38375.089406] a9bc  e3e00015 e28dd020 e8bd8070 c0a078b8 e59f3040 e1a00002 e92d4030 e24dd014[38375.097565] a9dc  e1a0100d e1a05002 e58d300c eb00e471 e2504000 da000004 e1a00005 e59f1018[38375.105724] a9fc  e3a02a01 e2844001 eb08794f e1a00004 e28dd014 e8bd8030 c0f42d98 c0d02180[38375.113887] [38375.113894] SP: 0xec89bdf0:[38375.118138] bdf0  00000000 00000003 00000001 00000000 ec89be2c c039898c 20000093 ffffffff[38375.126297] be10  ec89be5c c0f1f008 c11693d8 00000000 00000000 c0921418 c11093d8 00000000[38375.134456] be30  00000000 00000000 0016002c 00b00160 c11093d8 00000001 c0f1f008 c11693d8[38375.142616] be50  00000000 00000000 c60f3fc0 ec89be70 c017a99c c039898c 20000093 ffffffff[38375.150776] be70  00860000 c0896c84 2c000000 ec00bea4 00115238 00000000 00000000 00000015[38375.158937] be90  0000406a 10c5787d 00000000 00f00000 002c0000 00160003 ea006fc0 c1f193d8[38375.167096] beb0  00160001 c000f008 c11193d8 00000000 00000060 c010aa64 00000001 00000003[38375.175256] bed0  c0f28850 c08dc8a8 00000000 00000003 00000001 00000000 00000003 c0f1f008[38375.183416] [38375.183423] IP: 0xc60f3f40:[38375.187668] 3f40  01ffaaff c011cbe8 38a4f3f4 c5bde01c 02ffaaff c0115ed0 2107f3f5 fa00241c[38375.195830] 3f60  05ffaaff c0114e78 5a1ef3f6 00651916 01ffaaff c01160e0 efb1f3f7 fa002c04[38375.203988] 3f80  01ffaaff c011cbe8 38a4f3f8 c5bde01c 02ffaaff c0115f10 2107f3f9 fa003004[38375.212147] 3fa0  02ffaaff c01164f8 5a00f3fa fa892f00 c0bd8880 c0f18878 00b10040 c0a58874[38375.220307] 3fc0  e8ff80f8 c011e4a4 c10f4c5c 00115238 02ffaaff c0115f44 210ff3fd fa113000[38375.228468] 3fe0  05ffaaff c0114e78 5a1ef3fe 00000016 01ffaaff c01158e0 efb0f3ff fa002828[38375.236627] 4000  01ffaaff c01004a8 38a4f400 fa00300c 02ffaaff c0161de8 2107f401 c5a4c030[38375.244787] 4020  02ffaaff c011c92c 5a1ef402 c5bf4000 02ffaaff c0115914 efb0f403 fa002828[38375.252950] [38375.252957] R0: 0xc1109358:[38375.257201] 9358  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38375.265359] 9378  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38375.273520] 9398  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38375.281680] 93b8  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38375.289838] 93d8  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38375.297999] 93f8  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38375.306158] 9418  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38375.314318] 9438  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38375.322481] [38375.322487] R6: 0xc1109358:[38375.326731] 9358  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38375.334892] 9378  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38375.343049] 9398  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38375.351210] 93b8  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38375.359371] 93d8  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38375.367531] 93f8  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38375.375689] 9418  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38375.383849] 9438  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38375.392011] [38375.392017] R8: 0xc0f1ef88:[38375.396261] ef88  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38375.404423] efa8  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38375.412581] efc8  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38375.420741] efe8  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38375.428901] f008  00000009 0000000f 0000000f 00000009 00000000 ec827b80 ec827c00 ec827c80[38375.437061] f028  ec827d00 ec827d80 ec827e00 00000001 00000000 00005e37 c0c3b0cd c0c3b0e2[38375.445221] f048  c0c3b0ee c0c3b0fd c0c3b108 c0c3b113 c0c3b123 c0c3b12e c0c3b135 c0c3b141[38375.453381] f068  c0c3b149 c0c3b154 c0c3b162 c0c3b16d c0c3b17e c0c3b18f 00000000 000003e8[38375.461543] [38375.461549] R9: 0xc1169358:[38375.465793] 9358  00000000 00000000 c011a7b4 00000000 00000000 c011a674 00000000 00000000[38375.473954] 9378  00000000 00000000 00000000 00000000 c0119c80 c011a578 c0119b18 00000000[38375.482113] 9398  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000[38375.490274] 93b8  00000000 00000000 00000000 eca01990 ec411b80 20010000 00000001 ec0dd510[38375.498432] 93d8  00000000 ec9b66d0 174a174a 00000000 00000001 00000000 c5a2c380 c0176204[38375.506592] 93f8  00000000 fa00a664 00000000 ff81ff81 00000000 ec0e1bd0 ec0e1cc0 c0f341a0[38375.514752] 9418  c1e24a7c 0000000f ec8f8800 00000400 c1169428 c1169428 c017997c 825b825b[38375.522911] 9438  21532153 00000000 00030003 c1169444 c1169444 00000000 00020002 c1169454[38375.531083] Process swapper/3 (pid: 0, stack limit = 0xec89a2f0)[38375.537070] Stack: (0xec89be70 to 0xec89c000)[38375.541414] be60:                                     00860000 c0896c84 2c000000 ec00bea4[38375.549577] be80: 00115238 00000000 00000000 00000015 0000406a 10c5787d 00000000 00f00000[38375.557737] bea0: 002c0000 00160003 ea006fc0 c1f193d8 00160001 c000f008 c11193d8 00000000[38375.565897] bec0: 00000060 c010aa64 00000001 00000003 c0f28850 c08dc8a8 00000000 00000003[38375.574056] bee0: 00000001 00000000 00000003 c0f1f008 00000000 c017764c 976277bc 000022e6[38375.582216] bf00: 00000001 fffffff0 00000003 512f06f1 ec803180 c0178094 c1169488 eb9c62e0[38375.590376] bf20: 00000001 fffffff0 00000002 512f06f1 ec803180 c017b9b0 00790e3e eb9c62e0[38375.598535] bf40: 00000001 000008b6 00000003 00000ea6 002207cc 00000003 00000000 000008b6[38375.606698] bf60: 69367f90 00000003 c1169488 9704ae5e 000022e6 c31008a8 512f06f1 00000003[38375.614858] bf80: 00000000 c017bbbc 9704ae5e 000022e6 00000003 c31008a8 c10bd168 c31008a8[38375.623017] bfa0: c0f42f68 00000003 00000003 c0645bb8 c0645ba4 c0645fa4 c31008a8 c10bd168[38375.631177] bfc0: 00000003 c064616c 00000000 ec89a000 c10f4748 c0f286d0 c10f4a14 0000406a[38375.639336] bfe0: 00000000 c0106fa8 51000400 00000015 10c0387d 0090bf34 00000000 00000000[38375.641526] SMP: failed to stop secondary CPUs[38375.651948] [] (strcmp+0x8/0x3c) from [] (msm_pm_get_sleep_mode_value+0x40/0x70)[38375.661047] [] (msm_pm_get_sleep_mode_value+0x40/0x70) from [] (0xf00000)[38375.669542] Code: 1afffffa e12fff1e e3a03000 e7d02003 (e7d1c003) [38375.675650] CPU3: stopping[38375.678327] [] (unwind_backtrace+0x0/0x11c) from [] (handle_IPI+0x11c/0x1fc)[38375.687089] [] (handle_IPI+0x11c/0x1fc) from [] (gic_handle_irq+0x100/0x10c)[38375.695855] [] (gic_handle_irq+0x100/0x10c) from [] (__irq_svc+0x40/0x70)[38375.704343] Exception stack(0xec89bc80 to 0xec89bcc8)[38375.709387] bc80: c10f49e0 00000000 00020002 00010000 ec89be28 ec84f6c0 ec89a2f0 00000001[38375.717547] bca0: 00000005 00000028 00000005 00000000 00000000 ec89bcc8 c0109d40 c0920e9c[38375.725697] bcc0: 60000113 ffffffff[38375.729189] [] (__irq_svc+0x40/0x70) from [] (_raw_spin_unlock_irq+0x28/0x50)[38375.738050] [] (_raw_spin_unlock_irq+0x28/0x50) from [] (die+0x15c/0x1e0)[38375.746568] [] (die+0x15c/0x1e0) from [] (__do_kernel_fault.part.12+0x54/0x74)[38375.755500] [] (__do_kernel_fault.part.12+0x54/0x74) from [] (do_page_fault+0x394/0x3e8)[38375.765300] [] (do_page_fault+0x394/0x3e8) from [] (do_DataAbort+0x180/0x1ac)[38375.774153] [] (do_DataAbort+0x180/0x1ac) from [] (__dabt_svc+0x38/0x60)[38375.782555] Exception stack(0xec89be28 to 0xec89be70)[38375.787597] be20:                   c11093d8 00000000 00000000 00000000 0016002c 00b00160[38375.795758] be40: c11093d8 00000001 c0f1f008 c11693d8 00000000 00000000 c60f3fc0 ec89be70[38375.803913] be60: c017a99c c039898c 20000093 ffffffff[38375.808970] [] (__dabt_svc+0x38/0x60) from [] (strcmp+0x8/0x3c)[38375.816609] [] (strcmp+0x8/0x3c) from [] (msm_pm_get_sleep_mode_value+0x40/0x70)[38375.825715] [] (msm_pm_get_sleep_mode_value+0x40/0x70) from [] (0xf00000)[38377.501904] wcnss crash shutdown 0[38377.504277] Rebooting in 5 seconds..[38382.509218] Going down for restart now

REFERENCE:
kernel panic之後怎麼辦?

2014/08/27

無法安裝fastboot 更新 add-apt-repository

sudo apt-get install android-tools-fastboot

root@my-pc:~/$ sudo apt-get install android-tools-fastbootReading package lists... DoneBuilding dependency treeReading state information... DoneE: Unable to locate package android-tools-fastboot

參考一下 From Ubuntu wiki’s instructions
有一些步驟

Add PPAs (pre Trusty only)
The Phablet Tools PPA provides additional tools needed to install Ubuntu for devices . Tools are provided for installation on Ubuntu Desktop starting with 12.04 Precise.

You do not need to add the PPAs for Ubuntu Desktop 14.04 Trusty because the tools are available in the standard Ubuntu Universe archive component.

On your computer, press Ctrl+Alt+T to start a terminal.Add the Phablet Tools PPA as follows:$ sudo add-apt-repository ppa:phablet-team/toolsOn Ubuntu 12.04, you also must add the Ubuntu SDK Release PPA:$ sudo add-apt-repository ppa:ubuntu-sdk-team/ppaUpdate your system to use the latest packages:$ sudo apt-get update

然後再作一次

$ sudo apt-get install android-tools-fastboot

這段錯誤訊息 PM: Some devices failed to suspend 可能是wakeup_event的問題

會發生Error Message : [ 365.610079] PM: Some devices failed to suspend
關鍵是來自這段程式碼, 所以是wakeup_event的問題, 而非devices

if (pm_wakeup_pending()) {   printk(KERN_ERR "TTTTTT __device_suspend(),  Yes pm_wakeup_pending ..\n");    <===我加的 message   async_error = -EBUSY;   goto Complete;}

Android手持系統頻繁的進出suspend/resume狀況,
因此需要 pm_wakeup_pending() 機制, 用來檢查進入這段時間是否有被喚醒的事件發生
讓我們看程式碼

/*** pm_wakeup_pending - Check if power transition in progress should be aborted.** Compare the current number of registered wakeup events with its preserved value from the past and return true if new wakeup events have been registered* since the old value was stored.  Also return true if the current number of wakeup events being processed is different from zero.*/bool pm_wakeup_pending(void){    unsigned long flags;    bool ret = false;     spin_lock_irqsave(&events_lock, flags);    if (events_check_enabled) {          unsigned int cnt, inpr;          split_counters(&cnt, &inpr);          ret = (cnt != saved_count || inpr > 0);          events_check_enabled = !ret;     }     spin_unlock_irqrestore(&events_lock, flags);     return ret;}

如果註冊的wakeup events 數量有變化, 或是目前wakeup events 數大於0, 則 True
表示要終止 suspend, 即resume起來後再suspend動作
LOG參考如下:

[  285.370711] PM: suspend entry 2014-08-27 00:26:02.535471146 UTC   <=== 進入suspend動作[  285.377034] PM: Syncing filesystems ... done.[  285.423982] Freezing user space processes ... (elapsed 0.05 seconds) done.[  285.489518] Freezing remaining freezable tasks ... (elapsed 0.02 seconds) done.[  285.519359] Suspending console(s) (use no_console_suspend to debug)[  285.636368] TTTTTT __device_suspend(),  Yes pm_wakeup_pending ..   <===我加的 message[  285.636405] PM: Some devices failed to suspend!![  285.637872] [GPIO_KEY_WAKE] gpio:412, state:0[  285.637919] [GPIO_KEY_WAKE] gpio:409, state:0[  285.682804] hdmi_tx_hpd_on: HDMI HW version = 0x30000001[  285.761673] PM: resume of devices complete after 125.242 msecs[  285.792870] Restarting tasks ... done.[  285.808806] PM: suspend exit 2014-08-27 00:26:02.973608228 UTC[  285.814445] PM: suspend entry 2014-08-27 00:26:02.979247759 UTC   <=== 進入suspend動作[  285.820297] PM: Syncing filesystems ... done.[  285.833124] Freezing user space processes ... (elapsed 0.01 seconds) done.[  285.858165] Freezing remaining freezable tasks ... (elapsed 0.01 seconds) done.[  285.877691] Suspending console(s) (use no_console_suspend to debug)[  285.916006] [bq2419x_charger_read_status] Read Reg08=0x00, Reg09=0x00, stat_gpio:1/1, pg_gpio:1/1, hiz: 0/0[  285.970769] PM: suspend of devices complete after 84.786 msecs[  285.971882] PM: late suspend of devices complete after 1.104 msecs[  285.973659] PM: noirq suspend of devices complete after 1.766 msecs[  285.973666] Disabling non-boot CPUs ...[  285.973821] spmi_pmic_arb fc4cf000.qcom,spmi: int disable: invalid APID 256[  285.973848] CPU0: msm_cpu_pm_enter_sleep mode:3

怎麼看是哪個wakeup_source造成的呢?

看一下程式碼就知道是這個變數 combined_event_count
(這個變數即是記錄註冊wakeup_sources數與目前in progress wakeup_sources數)
有兩個fuctions會去更動combined_event_count變數 :
1. wakeup_source_activate
2. wakeup_source_deactivate

加入以下程式碼去看, 在sysc完後再出現的wakeup source name
(因為events_check_enabled會在sysc後才被設True)

if(events_check_enabled)    printk(KERN_ERR "TTTTTT wakeup_source_activate(), ws->name:%s\n", ws->name);

Example 如下:

/** * wakup_source_activate - Mark given wakeup source as active. * @ws: Wakeup source to handle. * * Update the @ws' statistics and, if @ws has just been activated, notify the PM * core of the event by incrementing the counter of of wakeup events being * processed. */static void wakeup_source_activate(struct wakeup_source *ws){	unsigned int cec;	ws->active = true;	ws->active_count++;	ws->last_time = ktime_get();	if (ws->autosleep_enabled)		ws->start_prevent_time = ws->last_time;	/* Increment the counter of events in progress. */	cec = atomic_inc_return(&combined_event_count);		if(events_check_enabled)		printk(KERN_ERR "TTTTTT wakeup_source_activate(),  ws->name:%s\n", ws->name);	trace_wakeup_source_activate(ws->name, cec);}

再一Example:

/** * wakup_source_deactivate - Mark given wakeup source as inactive. * @ws: Wakeup source to handle. * * Update the @ws' statistics and notify the PM core that the wakeup source has * become inactive by decrementing the counter of wakeup events being processed * and incrementing the counter of registered wakeup events. */static void wakeup_source_deactivate(struct wakeup_source *ws){	unsigned int cnt, inpr, cec;	ktime_t duration;	ktime_t now;	ws->relax_count++;	/*	 * __pm_relax() may be called directly or from a timer function.	 * If it is called directly right after the timer function has been	 * started, but before the timer function calls __pm_relax(), it is	 * possible that __pm_stay_awake() will be called in the meantime and	 * will set ws->active.  Then, ws->active may be cleared immediately	 * by the __pm_relax() called from the timer function, but in such a	 * case ws->relax_count will be different from ws->active_count.	 */	if (ws->relax_count != ws->active_count) {		ws->relax_count--;		return;	}	ws->active = false;	now = ktime_get();	duration = ktime_sub(now, ws->last_time);	ws->total_time = ktime_add(ws->total_time, duration);	if (ktime_to_ns(duration) > ktime_to_ns(ws->max_time))		ws->max_time = duration;	ws->last_time = now;	del_timer(&ws->timer);	ws->timer_expires = 0;	if (ws->autosleep_enabled)		update_prevent_sleep_time(ws, now);	/*	 * Increment the counter of registered wakeup events and decrement the	 * couter of wakeup events in progress simultaneously.	 */	cec = atomic_add_return(MAX_IN_PROGRESS, &combined_event_count);	trace_wakeup_source_deactivate(ws->name, cec);	if(events_check_enabled)		printk(KERN_ERR "TTTTTT wakeup_source_deactivate(),  ws->name:%s\n", ws->name);	split_counters(&cnt, &inpr);	if (!inpr && waitqueue_active(&wakeup_count_wait_queue))		wake_up(&wakeup_count_wait_queue);}

我的測試結果找出 event1-1202

<6>[  413.371801] Suspending console(s) (use no_console_suspend to debug)<3>[  413.412673] TTTTTT wakeup_source_activate(),  ws->name:event1-1202<3>[  413.454422] TTTTTT __device_suspend(),  Yes pm_wakeup_pending ..<3>[  413.454430] PM: Some devices failed to suspend<6>[  413.802075] PM: resume of devices complete after 347.632 msecs<6>[  413.825610] Restarting tasks ... done.<6>[  413.839963] PM: suspend exit 1970-01-02 00:08:03.900456038 UTC<6>[  413.845279] PM: suspend entry 1970-01-02 00:08:03.905786559 UTC<6>[  413.851261] PM: Syncing filesystems ... done.<6>[  413.864707] Freezing user space processes ... (elapsed 0.02 seconds) done.<6>[  413.891142] Freezing remaining freezable tasks ... (elapsed 0.01 seconds) done.

#adb shell cat /sys/kernel/debug/wakeup_sources

 name                           active_count    event_count     wakeup_count    expire_count    active_since    total_time      max_time        last_change     prevent_suspend_time
ipc000000c7_sensors.qcom 0 0 0 0 0 0 0 650757 0
ipc000000c6_sensors.qcom 20 20 0 0 0 1 0 652384 0
ipc000000c5_sensors.qcom 0 0 0 0 0 0 0 650726 0
ipc000000c4_sensors.qcom 1 1 0 0 0 5 5 650732 0
rmt_storage_-1223766296 1 1 0 0 0 147 147 101285 0
PowerManagerService.Broadcasts 14 14 0 0 0 4579 573 651072 946
ipc000000ab_Thread-40 8 8 0 0 0 0 0 427711 0
ipc000000aa_Thread-40 1 1 0 0 0 0 0 16770 0
ipc000000a7_Thread-33 8 8 0 0 0 1 0 427711 0
ipc000000a6_Thread-33 1 1 0 0 0 0 0 16593 0
ipc000000a5_Thread-33 0 0 0 0 0 0 0 16509 0
ipc000000a2_Loc_hal_worker 8 8 0 0 0 0 0 427711 0
ipc000000a1_Loc_hal_worker 34 44 0 0 0 3 1 650803 0
ipc000000a0_Loc_hal_worker 0 0 0 0 0 0 0 16172 0
PowerManagerService.WakeLocks 42 42 0 0 0 48679 35780 651106 34599
event4-1202 15 15 0 0 0 952 327 414204 952
event0-1202 27 27 0 0 0 1789 397 414204 1785
event1-1202 89 99 16 0 0 3259 425 416181 3247
event2-1202 10 10 0 0 0 1784 396 414204 1784
event3-1202 12 12 0 0 0 121 91 414450 100
event5-1202 15 15 0 0 0 949 327 414204 949
event6-1202 0 0 0 0 0 0 0 15297 0
KeyEvents 162 162 0 0 0 303 141 646073 104
PowerManagerService.Display 8 8 0 0 1842 65335 13986 650571 186
ipc0000008d_sensors.qcom 8 8 0 0 0 0 0 427711 0
ipc0000008c_sensors.qcom 15 15 0 0 0 1 0 650757 0
ipc0000008b_sensors.qcom 8 8 0 0 0 0 0 427711 0
ipc0000008a_sensors.qcom 0 0 0 0 0 0 0 13073 0
qcril 51 51 0 0 0 542 55 651112 151
ipc00000087_thermal-engine 8 8 0 0 0 0 0 427711 0
ipc00000086_thermal-engine 3 3 0 0 0 0 0 12704 0
ipc00000085_thermal-engine 8 8 0 0 0 0 0 427711 0
ipc00000084_thermal-engine 2 2 0 0 0 0 0 12704 0
qmuxd_port_wl_7 21 21 0 0 0 0 0 16728 0
smdcntl7 21 37 0 0 0 1 0 16728 0
qmuxd_port_wl_6 21 21 0 0 0 0 0 16727 0
smdcntl6 21 34 0 0 0 1 0 16727 0
qmuxd_port_wl_5 21 21 0 0 0 0 0 16726 0
smdcntl5 21 35 0 0 0 1 0 16726 0
qmuxd_port_wl_4 21 21 0 0 0 0 0 16725 0
smdcntl4 21 33 0 0 0 1 0 16725 0
qmuxd_port_wl_3 21 21 0 0 0 0 0 16723 0
smdcntl3 21 33 0 0 0 1 0 16722 0
qmuxd_port_wl_2 21 21 0 0 0 0 0 16720 0
smdcntl2 21 34 0 0 0 1 0 16720 0
qmuxd_port_wl_1 64 64 0 0 0 8 1 651102 6
smdcntl1 57 94 0 0 0 8 0 651101 5
ipc00000083_time_daemon 8 8 0 0 0 0 0 427711 0
ipc00000082_time_daemon 1 1 0 0 0 0 0 11697 0
qmuxd_port_wl_0 300 300 0 0 0 25 0 651110 5
ipc0000003b_sensors.qcom 11 11 0 0 0 21 21 427711 0
ipc0000003a_sensors.qcom 0 0 0 0 0 0 0 11030 0
ipc00000039_sensors.qcom 11 11 0 0 0 3 2 427711 0
ipc00000038_sensors.qcom 1 1 0 0 0 0 0 101033 0
ipc00000037_sensors.qcom 11 11 0 0 0 2 2 427711 0
ipc00000036_sensors.qcom 1 1 0 0 0 0 0 11036 0
ipc00000035_sensors.qcom 12 12 0 0 0 0 0 427711 0
ipc00000034_sensors.qcom 0 0 0 0 0 0 0 11029 0
ipc00000033_sensors.qcom 13 13 0 0 0 0 0 427711 0
ipc00000032_sensors.qcom 0 0 0 0 0 0 0 11028 0
ipc00000031_sensors.qcom 14 14 0 0 0 0 0 427711 0
ipc00000030_sensors.qcom 0 0 0 0 0 0 0 11028 0
ipc0000002f_sensors.qcom 15 15 0 0 0 0 0 427711 0
ipc0000002e_sensors.qcom 0 0 0 0 0 0 0 11027 0
ipc0000002d_sensors.qcom 16 16 0 0 0 0 0 427711 0
ipc0000002c_sensors.qcom 0 0 0 0 0 0 0 11027 0
ipc0000002b_sensors.qcom 17 17 0 0 0 0 0 427711 0
ipc0000002a_sensors.qcom 0 0 0 0 0 0 0 11027 0
ipc00000029_sensors.qcom 18 18 0 0 0 1 0 427711 0
ipc00000028_sensors.qcom 0 0 0 0 0 0 0 11026 0
ipc00000027_sensors.qcom 19 19 0 0 0 0 0 427711 0
ipc00000026_sensors.qcom 0 0 0 0 0 0 0 11026 0
ipc00000025_sensors.qcom 20 20 0 0 0 1 0 427710 0
ipc00000024_sensors.qcom 0 0 0 0 0 0 0 11025 0
ipc00000023_sensors.qcom 20 20 0 0 0 0 0 427710 0
ipc00000022_sensors.qcom 9 9 0 0 0 0 0 11025 0
DIAG_DCI_WS 0 0 0 0 0 0 0 10916 0
DIAG_DCI_CMD_WS 0 0 0 0 0 0 0 10916 0
ipc0000001f_sensors.qcom 53 53 0 0 0 1 0 427710 0
ipc0000001e_sensors.qcom 6 6 0 0 0 0 0 11021 0
ipc0000001d_sensors.qcom 0 0 0 0 0 0 0 10855 0
ipc0000001a_sensors.qcom 54 54 0 0 0 20 17 427710 0
ipc00000019_sensors.qcom 15 15 0 0 0 1 0 650726 0
rmt_storage_-1223765448 2 2 0 0 0 28 28 10842 0
ipc00000018_ims_rtp_daemon 54 57 0 0 0 6 2 427710 0
ipc00000017_ims_rtp_daemon 0 0 0 0 0 0 0 10759 0
ipc_rtr_smd_ipcrtr 69 80 0 0 0 2 0 650803 0
radio-interface 11 28 0 0 0 15294 4076 652093 1000
qcril_pre_client_init 1 1 0 0 0 3037 3037 12739 0
ipc00000016_rmt_storage 54 63 0 0 0 1184 1178 427710 0
ipc00000015_rmt_storage 9 9 0 0 0 0 0 101137 0
ipc00000014_imsdatadaemon 54 63 0 0 0 1185 1180 427710 0
ipc00000013_imsdatadaemon 0 0 0 0 0 0 0 9376 0
ipc00000012_sensors.qcom 49 63 0 0 0 1353 1338 427710 0
ipc00000011_sensors.qcom 62 62 0 0 0 162 160 650756 0
ipc_rtr_wcnss_ipcrtr 2 3 0 0 0 2 2 9516 0
wcnss 0 0 0 0 0 0 0 8650 0
ipc00000010_time_daemon 0 0 0 0 0 0 0 8570 0
ipc0000000f_time_daemon 56 63 0 0 0 8 2 427710 0
ipc0000000e_time_daemon 0 0 0 0 0 0 0 8570 0
smdcntl0 289 392 0 0 0 41 4 651110 5
ipc0000000d_thermal-engine 63 63 0 0 0 1 0 427710 0
ipc0000000c_thermal-engine 0 0 0 0 0 0 0 8540 0
ipc00000009_thermal-engine 59 63 0 0 0 3 1 427710 0
ipc00000008_thermal-engine 0 0 0 0 0 0 0 8536 0
ipc00000007_thermal-engine 0 0 0 0 0 0 0 8535 0
ipc00000004_rfs_access 56 63 0 0 0 1187 1177 427710 0
ipc00000003_rfs_access 0 0 0 0 0 0 0 8483 0
taiko-slim-pgd 0 0 0 0 0 0 0 8280 0
ipc00000001_kworker/0:3 7 7 0 0 0 0 0 270041 0
ipc_rtr_q6_ipcrtr 1038 1051 0 0 0 38 1 652384 0
gpio_keys.81 0 0 0 0 0 0 0 5846 0
bam_dmux_wakelock 2 2 0 0 0 4001 2001 15602 0
coresight-etm 0 0 0 0 0 0 0 5547 0
coresight-etm 0 0 0 0 0 0 0 5536 0
coresight-etm 0 0 0 0 0 0 0 5526 0
coresight-etm 0 0 0 0 0 0 0 5516 0
qpnp-power-on-ec947800 0 0 0 0 0 0 0 5307 0
mmc0_detect 1 1 0 1 0 496 496 5470 0
msm_smd_Tx 0 0 0 0 0 0 0 4654 0
msm_smd_Rx 0 0 0 0 0 0 0 4654 0
qpnp-iadc-ec948a00 2 2 0 0 0 19 9 605930 9
qpnp-vadc-ec948800 51 51 0 0 0 292 21 651367 69
power-supply 15 15 0 0 0 24 4 651364 10
bq2419x_eoc 5 17 0 0 2258 626559 257916 650156 562347
bq2419x_usb 8 9 0 8 0 8525 1552 651580 1044
power-supply 2 2 0 0 0 0 0 5020 0
bq27529_fw_update 0 0 0 0 0 0 0 4172 0
video2 0 0 0 0 0 0 0 4067 0
video1 0 0 0 0 0 0 0 4017 0
qpnp-rtc-ec948600 0 0 0 0 0 0 0 3736 0
alarm 19 19 1 0 0 765 474 649939 760
alarm_rtc 3 3 0 0 0 6 6 13894 0
msm_dwc3 8 8 0 0 2144 628464 259752 650271 562561
power-supply 44 97 0 0 0 448 41 651368 157
diag_nrt_wcnss_read 0 0 0 0 0 0 0 2660 0
diag_nrt_lpass_read 0 0 0 0 0 0 0 2660 0
diag_nrt_modem_read 0 0 0 0 0 0 0 2660 0
msm_serial_hs_dma 2 2 0 0 0 8 5 8396 0
msm_serial_hs_rx 1 8 0 1 0 499 499 8890 0
qmi2 0 0 0 0 0 0 0 290 0
qmi1 0 0 0 0 0 0 0 290 0
qmi0 0 0 0 0 0 0 0 290 0
ssr(venus) 0 0 0 0 0 0 0 285 0
pil-venus 0 0 0 0 0 0 0 285 0
ssr(wcnss) 0 0 0 0 0 0 0 284 0
pil-wcnss 1 1 0 0 0 592 592 9513 0
ssr(modem) 0 0 0 0 0 0 0 282 0
pil-modem 0 0 0 0 0 0 0 282 0
pil-mba 1 1 0 0 0 2151 2151 10744 0
ssr(adsp) 0 0 0 0 0 0 0 281 0
pil-adsp 1 1 0 0 0 182 182 8174 0
smsm_snapshot 11 11 0 0 0 27 26 15602 0
autosleep 15 15 0 0 0 1 1 650724 1

2014/08/25

Unix 與 MS-DOS 指令對照表 (Linux v.s Windows)

最近作一些專案兩個平台都會用到, 所以只熟悉UNIX的指令不夠用, 為了更有效率工作, 也得把windows指令記一下, 反正常用就知道了! 部分內容參考這裡 ..

.
.

Unix

MS-DOS

 說   明  例          子 
cdcd進入目錄cd ..
mkdirmd開子目錄mkdir hello
pwdcd顯示目前目錄pwd
envset顯示目前環境變數env
setenvset設定環境變數setenv pp pwd
rmdel殺檔案rm -r hello
cat/moretype顯示檔案內容more .login
lsdir顯示檔案ls
lpprint列印檔案lp .login
cpcopy複製檔案cp .login anotherfile
datedate/time時間顯示.設定date
mvren移動,重新命名檔案mv .login .login.orig
manhelp線上指令查詢man ps
passwd改變密碼
mail電子郵件
write傳送訊息給目前線上使用者
ps顯示 processes
find顯示 processes

2014/08/22

使用script檔去作android monkey 測試

Monkey是Android系统固件自带的性能测试工具,他可以模拟各种按键、触屏、轨迹球、activity等事件。

Android官方正式介紹Monkey說明於此, 但今天比較想著墨於script的使用, 有了script就可以把要讓android作的測試都寫在裡面

—–

先看看指令裡怎麼說明的 (PS: 以下說明為adb使用於Windows作業系統平台)

C:\Windows\System32>adb shell monkey --help** Error: Unknown option: --helpusage: monkey [-p ALLOWED_PACKAGE [-p ALLOWED_PACKAGE] ...]              [-c MAIN_CATEGORY [-c MAIN_CATEGORY] ...]              [--ignore-crashes] [--ignore-timeouts]              [--ignore-security-exceptions]              [--monitor-native-crashes] [--ignore-native-crashes]              [--kill-process-after-error] [--hprof]              [--pct-touch PERCENT] [--pct-motion PERCENT]              [--pct-trackball PERCENT] [--pct-syskeys PERCENT]              [--pct-nav PERCENT] [--pct-majornav PERCENT]              [--pct-appswitch PERCENT] [--pct-flip PERCENT]              [--pct-anyevent PERCENT] [--pct-pinchzoom PERCENT]              [--pkg-blacklist-file PACKAGE_BLACKLIST_FILE]              [--pkg-whitelist-file PACKAGE_WHITELIST_FILE]              [--wait-dbg] [--dbg-no-events]              [--setup scriptfile] [-f scriptfile [-f scriptfile] ...]              [--port port]              [-s SEED] [-v [-v] ...]              [--throttle MILLISEC] [--randomize-throttle]              [--profile-wait MILLISEC]              [--device-sleep-time MILLISEC]              [--randomize-script]              [--script-log]              [--bugreport]              [--periodic-bugreport]              COUNT

運行monkey可以採用兩種方式:系統默認(Default)方式和script方式

一、默認(Default)運行方式:

# adb shell monkey -p package.name -v 30其中: 可以繼續添加一個或者兩個-v 參數, -v參數越多,輸出的日誌越詳細; 最後的數字表示,觸發的事件次數# adb shell monkey -p package.name -v 30 > log.txt為了更好的查看日誌,可以將輸出的日誌信息重定向到文件中

二、腳本方式

Android 的monkey test 工具提供了-f scriptfile 參數,可以指定test 腳本。
在monkey 的源碼MonkeySourceScript.java 中有一小段註釋,
檔案位置 development/cmds/monkey/src/com/android/commands/monkey/MonkeySourceScript.java

裡面給了一個不到10 行例子:

/** * monkey event queue. It takes a script to produce events sample script format: * * type= raw events * count= 10 * speed0 * start data >> * captureDispatchPointer(5109520,5109520,0,230.75429,458.1814,0.20784314,0.06666667,0,0.0,0.0,65539,0) * captureDispatchKey(5113146,5113146,0,20,0,0,0,0) * captureDispatchFlip(true) * ... *  */

monkey中提供的函數如下:

DispatchPointer(long downTime, long eventTime, int action, float x, float y, float pressure, float size, int metaState, float xPrecision, float yPrecision, int device, int edgeFlags)DispatchTrackball(long downTime, long eventTime, int action, float x, float y, float pressure, float size, int metaState, float xPrecision, float yPrecision, int device, int edgeFlags)DispatchKey(long downTime, long eventTime, int action, int code, int repeat, int metaState, int device, int scancode)DispatchFlip(boolean keyboardOpen)DispatchPress(int keyCode)LaunchActivity(String pkg_name, String cl_name)UserWait(long sleeptime)LongPress(int keyCode)

首先本地編寫需要的測試的事件命名為monkey.script (文件格式無要求)

將文件push到手機或模擬器的sdcard中# adb push monkey.script /sdcard/然後執行腳本:# adb shell monkey -v -f /sdcard/monkey.script

附 Example1:

type= usercount= 49speed= 1.0start data >>LaunchActivity(com.example.android.notepad, com.example.android.notepad.NotesList)DispatchPress(KEYCODE_DPAD_DOWN)LongPress(KEYCODE_DOWN)DispatchPress(KEYCODE_BACK)

其中type值可以任意,源碼中沒有對該值做任何處理。
count值,在此無效,還是需要在命令行輸入需要執行的次數。因為命令行的count值是必填項

附 Example2: OnOffWlan.script
要開關wifi的觸控步驟..

type=raw eventscount= 1speed= 1.0start data >>DispatchPress(KEYCODE_HOME)captureUserWait ( 1000 )captureDispatchPointer( 459755113000,459755113000, 0, 546, 34,0.20784314,0.06666667,0,0.0,0.0,65539,0)captureUserWait ( 1000 )captureDispatchPointer( 459755113000,459755113000, 2, 534, 1481,0.20784314,0.06666667,0,0.0,0.0,65539,0)captureDispatchPointer( 459755113000,459755113000, 1, 534, 1481,0.20784314,0.06666667,0,0.0,0.0,65539,0)captureUserWait ( 1000 )captureDispatchPointer( 11368012663000,11368171949000, 0, 1001, 65,0.20784314,0.06666667,0,0.0,0.0,65539,0)captureDispatchPointer( 11368012663000,11368171949000, 1, 1001, 65,0.20784314,0.06666667,0,0.0,0.0,65539,0)captureUserWait ( 1000 )captureDispatchPointer( 459755113000,459755113000, 0, 181, 695,0.20784314,0.06666667,0,0.0,0.0,65539,0)captureUserWait ( 2000 )captureDispatchPointer( 459755113000,459755113000, 1, 181, 695,0.20784314,0.06666667,0,0.0,0.0,65539,0)captureUserWait ( 3000 )DispatchPress(KEYCODE_BACK)captureDispatchPointer( 459755113000,459755113000, 0, 546, 34,0.20784314,0.06666667,0,0.0,0.0,65539,0)captureUserWait ( 1000 )captureDispatchPointer( 459755113000,459755113000, 2, 534, 1481,0.20784314,0.06666667,0,0.0,0.0,65539,0)captureDispatchPointer( 459755113000,459755113000, 1, 534, 1481,0.20784314,0.06666667,0,0.0,0.0,65539,0)captureUserWait ( 1000 )captureDispatchPointer( 11368012663000,11368171949000, 0, 1001, 65,0.20784314,0.06666667,0,0.0,0.0,65539,0)captureDispatchPointer( 11368012663000,11368171949000, 1, 1001, 65,0.20784314,0.06666667,0,0.0,0.0,65539,0)captureUserWait ( 1000 )captureDispatchPointer( 459755113000,459755113000, 0, 181, 695,0.20784314,0.06666667,0,0.0,0.0,65539,0)captureUserWait ( 2000 )captureDispatchPointer( 459755113000,459755113000, 1, 181, 695,0.20784314,0.06666667,0,0.0,0.0,65539,0)captureUserWait ( 3000 )DispatchPress(KEYCODE_BACK)

以下為Example2執行時的 LOG:
看這個LOG 你就可以知道如何設定touch的點, Action是Up/Down/Move
就可以模擬真人使用的步驟, 當然.要算好(x, y)的座標…
指令 #adb shell monkey -v -f /storage/sdcard0/Download/OnOffWlan.script 100
表示要顯示log(-v), 使用script(-f), 運行100次

C:\> adb shell monkey -v -f /storage/sdcard0/Download/OnOffWlan.script  100:Monkey: seed=1409796926274 count=100:IncludeCategory: android.intent.category.LAUNCHER:IncludeCategory: android.intent.category.MONKEYReplaying 1 events with speed 1.0    // Allowing start of Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] cmp=com.android.launcher/com.android.launcher2.Launcher } in package com.android.launcher    // Allowing start of Intent { act=android.intent.action.CHOOSER cmp=android/com.android.internal.app.ChooserActivity } in package android:Sending Touch (ACTION_DOWN): 0:(546.0,34.0):Sending Touch (ACTION_MOVE): 0:(534.0,1481.0):Sending Touch (ACTION_UP): 0:(534.0,1481.0):Sending Touch (ACTION_DOWN): 0:(1001.0,65.0):Sending Touch (ACTION_UP): 0:(1001.0,65.0):Sending Touch (ACTION_DOWN): 0:(181.0,695.0)    // Allowing start of Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] cmp=com.android.launcher/com.android.launcher2.Launcher } in package com.android.launcher:Sending Touch (ACTION_UP): 0:(181.0,695.0):Sending Touch (ACTION_DOWN): 0:(546.0,34.0):Sending Touch (ACTION_MOVE): 0:(534.0,1481.0):Sending Touch (ACTION_UP): 0:(534.0,1481.0):Sending Touch (ACTION_DOWN): 0:(1001.0,65.0):Sending Touch (ACTION_UP): 0:(1001.0,65.0):Sending Touch (ACTION_DOWN): 0:(181.0,695.0)    // Allowing start of Intent { act=android.intent.action.CHOOSER cmp=android/com.android.internal.app.ChooserActivity } in package android    // activityResuming(com.android.launcher):Sending Touch (ACTION_UP): 0:(181.0,695.0)

reference:
Monkey Script
Android自动化测试 monkey 工具学习 系列5