2014年12月10日 星期三

[轉] 使用handler.obtainMessage() 時要注意的問題

handler.obtainMessage() 的作用是從當前的Handler中獲取指定的Message以供再次使用
尤其是在監測線程中 如果不斷的new Message() 可能出現錯誤 (錯誤信息已經忘了 沒有記錄 =.=)
有5個重載的方法
[java] view plaincopy
  1. public final Message obtainMessage ()   
  2. public final Message obtainMessage (int what)  
  3. public final Message obtainMessage (int what, Object obj)  
  4. public final Message obtainMessage (int what, int arg1, int arg2)  
  5. public final Message obtainMessage (int what, int arg1, int arg2, Object obj)  
what  arg1 arg2 obj分別對應Message中的相應成員變量
並且這樣獲得的Message不用再重新定義相應的值  十分好用 
一般來講 what是用來switch不同的操作 而其他3個參數都是定義屬性

要注意的是 具有兩個參數的方法只有一個 且第二個參數是Object 而不是arg1
並且如果在2個參數的方法中 將第二個參數填寫為本應該設置為arg1的值(int)時候 也不會報錯 因為:
1. arg1有缺省值0
2. int型可以被自動轉化為Integer
但是arg1的值卻被賦給了msg,obj 所以在Handler中的arg1值就為0了

[轉] Android 的消息隊列模型

Android 的消息隊列模型

Android是參考Windows的消息循環機制來實現Android自身的消息循環的。
Android通過Looper、Handler來實現消息循環機制,Android消息循環是針對線程的(每個線程都可以有自己的消息隊列和消息循環)。
Android系統中,Looper負責管理線程的消息隊列和消息循環。我們可以通過Loop.myLooper()得到當前線程的Looper對象,通過Loop.getMainLooper()可以獲得當前進程的主線程的Looper對象。
一個線程可以存在(當然也可以不存在)一個消息隊列和一個消息循環(Looper)。
Activity是一個UI線程,運行於主線程中,Android系統在啟動的時候會為Activity創建一個消息隊列和消息循環(Looper)。
Handler的作用是把消息加入特定的(Looper)消息隊列中,並分發和處理該消息隊列中的消息。構造Handler的時候可以指定一個Looper對象,如果不指定則利用當前線程的Looper創建。
Activity、Looper、Handler,Thread的關係如下圖所示:
image
一個Activity中可以創建多個工作線程或者其他的組件,如果這些線程或者組件把他們的消息放入Activity的主線程消息隊列,那麼該消息就會在主線程中處理了。
因為主線程一般負責界面的更新操作,並且Android系統中的widget不是線程安全的,所以這種方式可以很好的實現Android界面更新。在Android系統中這種方式有著廣泛的運用。
那麼一個線程怎樣把消息放入主線程的消息隊列呢?答案是通過Handle對象,只要Handler對象以主線程的Looper創建,那麼調用Handler的sendMessage等接口,將會把消息放入隊列都將是放入主線程的消息隊列。並且將會在Handler主線程中調用該handler的handleMessage接口來處理消息。
更多Android消息隊列的信息請參看: http://my.unix-center.net/~Simon_fu/?p=652
下面這個圖從另外一個角度描述了他們的關係:
image

2014年11月25日 星期二

[轉] kernel build system探索

vmlinux是如何煉成的-- kernel makefile

引子
kernelmakefile包含的內容還真是多,我就是想看看要是我自己添加一個目錄編譯到內核裡,要怎麼做
就是這麼個不起眼的實驗,引發了一堆的故事

最簡單的例子
添加 一個目錄,叫test, 添加了test.c 和 Makefile
文件內容很簡單,如下。
cat Makefile
#
# Makefile for the linux kernel makefile experiment.
#
obj-y := test.o
cat test.c
#include <linux/export.h>
int test_global = 0;
然後在主 Makefile中 添加
-core-y         += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
+core-y         += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ test/
最後 make test
make[1]: Nothing to be done for `all'.
  HOSTCC arch/x86/tools/relocs
  CHK include/linux/version.h
  CHK include/generated/utsrelease.h
  CC kernel/bounds.s
  GEN include/generated/bounds.h
  CC arch/x86/kernel/asm-offsets.s
  GEN     include/generated/asm-offsets.h
  CALL    scripts/checksyscalls.sh
  CC      test/test.o
  LD      test/built-in.o
恩,不錯,可以了。

vmlinux是如何煉成的-- kernel makefile
人總是不知足的,我又開始好奇,這build的過程究竟是怎麼個回事
好吧,我們知make後,最終的結果vmlinux,那我們就找找這個神奇的東西是
產生的吧。 
vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)
$(sort $(vmlinux-deps)): $(vmlinux-dirs) ;
vmlinux: scripts/link-vmlinux.sh $(vmlinux-deps) FORCE
ifdef CONFIG_HEADERS_CHECK
    $(Q)$(MAKE) -f $(srctree)/Makefile headers_check
endif
ifdef CONFIG_SAMPLES
    $(Q)$(MAKE) $(build)=samples
endif
ifdef CONFIG_BUILD_DOCSRC
    $(Q)$(MAKE) $(build)=Documentation
endif
    +$(call if_changed,link-vmlinux)

vmlinx 基於上面三個目標, 而vmlinux-deps又基於 $(vmlinux-dirs)。 恩,好複雜。
那來看vmlinux-dirs都包含什麼吧。
在主Makefile中看到下面的內容。
core-y        += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ test/

vmlinux-dirs    := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
             $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
             $(net-y) $(net-m) $(libs-y) $(libs-m)))
$(vmlinux-dirs): prepare scripts
    $(Q)$(MAKE) $(build)=$@
恩, 我們vmlinux-dirs的東東打印出來看看。
vmlinux-dris: init usr arch/x86 kernel mm fs ipc security crypto block test drivers sound firmware arch/x86/pci arch/x86/power arch/x86/video arch/x86/oprofile net lib arch/x86/lib
這樣,你是不是明白點了呢。 這些都kernel源代碼中子目錄。也就kernel將要挨
進入每個子目錄,編譯~。
那最後這vmlinux是怎麼生成的呢? 怎麼樣將每個目錄下生成的模塊鏈接成一vmlinux的文件的呢
看到上vmlinux目標中,最後一個命令
+$(call if_changed,link-vmlinux)
哦,原來是調用cmd_link-vmlinux。這個命令就定義在Makefile
      cmd_link-vmlinux = $(CONFIG_SHELL) $< $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux)
打出來看看,長這樣。
      /bin/bash $<  ld -m elf_i386 --emit-relocs --build-id
$< 表示第一個以來目標,那麼vmlinux目標中,第一個目標是 scripts/link-vmlinux.sh, 展開後就成為。
/bin/bash scripts/link-vmlinux.sh ld -m elf_i386 --emit-relocs --build-id
額,原來是又調用了一個腳本。。。 好吧, 再進去看看。  發現這麼個東東
info LD vmlinux
vmlinux_link "${kallsymso}" vmlinux
vmlinux_link()
{
    local lds="${objtree}/${KBUILD_LDS}"

    if [ "${SRCARCH}" != "um" ]; then
        ${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2}                  \
            -T ${lds} ${KBUILD_VMLINUX_INIT}                     \
            --start-group ${KBUILD_VMLINUX_MAIN} --end-group ${1}
    else
        ${CC} ${CFLAGS_vmlinux} -o ${2}                              \
            -Wl,-T,${lds} ${KBUILD_VMLINUX_INIT}                 \
            -Wl,--start-group                                    \
                 ${KBUILD_VMLINUX_MAIN}                      \
            -Wl,--end-group                                      \
            -lutil ${1}
        rm -f linux
    fi
}
好吧,原來是調用了這個函數。。。 打出來看看吧。
ld -m elf_i386 --emit-relocs --build-id -o vmlinux -T arch/x86/kernel/head_32.o arch/x86/kernel/head32.o arch/x86/kernel/head.o init/built-in.o --start-group usr/built-in.o arch/x86/built-in.o kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o crypto/built-in.o block/built-in.o test/built-in.o lib/lib.a arch/x86/lib/lib.a lib/built-in.o arch/x86/lib/built-in.o drivers/built-in.o sound/built-in.o firmware/built-in.o arch/x86/pci/built-in.o arch/x86/power/built-in.o arch/x86/video/built-in.o net/built-in.o --end-group .tmp_kallsyms2.o
恩,原來真相是這樣的。 最後把這麼多東西鏈接起來vmlinux。 看到我們添加test目錄了麼,它也生成了一built-in.o,最後鏈接到vmlinux
$ nm vmlinux | grep test_global
c198d284 B test_global

啊哦,還真有這個symbol

神秘的built-in.o
在最後的鏈接過程中,我們可以看到,幾乎所有的依賴條件中,都會生成built-in.o的文件。 那這個文件,是怎麼生成的呢?
$(vmlinux-dirs): prepare scripts
    $(Q)$(MAKE) $(build)=$@
從這個規則中可以看到vmlinux-dir目標是通過下面make來生成的。展開一下看看。 這buildscripts/Kbuild.include
make -f scripts/Makefile.build obj=$@
對應到test目錄 那就是
make -f scripts/Makefile.build obj=test
這麼看來,就要進scripts/Makefile.build文件了
PHONY := __build
__build:
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
     $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
     $(subdir-ym) $(always)
    @:
__build是這makefile的第一個目標,也是默認的目標。 這裡面藏著一builtin-target,看著很像,再搜搜
ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(subdir-m) $(lib-target)),)
builtin-target := $(obj)/built-in.o
endif
恩 原來這個就是這麼built-in.o的原因。但是要buit-in.o,必須要以上的這些變量不能全部為空
那再來看看編譯這built-in.o的規則是什
quiet_cmd_link_o_target = LD      $@
# If the list of objects to link is empty, just create an empty built-in.o
cmd_link_o_target = $(if $(strip $(obj-y)),\
              $(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) \
              $(cmd_secanalysis),\
              rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@)

$(builtin-target): $(obj-y) FORCE
    $(call if_changed,link_o_target)

targets += $(builtin-target)
恩,基本明白了,就是obj-y的內容不為空,那麼就ld來鏈接成一built-in.o
但是我試了一下,如果沒obj-y那麼,也會生成built-in.o,但是用的是別的命令
如在i386下,用的是
rm -f test/built-in.o; ar rcsD test/built-in.o
不知道這個是什麼高級玩意。
好了,到此為止,基本上一個最上層的框架有了一個概念。 那就先休息一下~

一切盡在掌握 -- kconfig 配置系統

kconfig是個強大的工具,如果makefile制定了完美的編譯依賴關系,那kconfig制定了完美的模塊的依賴關係
源頭
在根目錄下有Kconfig文件,這就是一切故事的起源
整個文件就沒幾行,打出來看一眼。
#
# For a description of the syntax of this configuration file,
# see Documentation/kbuild/kconfig-language.txt.
#
mainmenu "Linux/$ARCH $KERNELVERSION Kernel Configuration"

config SRCARCH
    string
    option env="SRCARCH"
source "arch/$SRCARCH/Kconfig"
第一行就是輸出個內核版本號。
第二行應該是配置一個環境變量? 不知道,以後再來看。
第三行很重要,這個是包含了一arch目錄下Kconfig文件

當你打開這個文件的時候,你就發現這是一切的開始
我們運行make menuconfig, 你可以看到,這個文件就是make menuconfig中顯示的東西。
一切都變得明朗起來,你是否有種太極生兩儀,兩儀生四象,四象生八卦的神奇感

剪不斷,理還亂
kernel中這麼多的模塊之間的依賴關係,簡直就是 剪不斷,理還亂。
幸好Kconfig文件中,我們可以找到一點蛛絲馬
依賴 depends on
這個關鍵字表示了在某些配置選中後,本配置項才會顯
在 driver/pci/Kconfig文件中
config PCI_MSI
    bool "Message Signaled Interrupts (MSI and MSI-X)"
    depends on PCI
    depends on ARCH_SUPPORTS_MSI

可以發現,要配MSI必須要先支PCI。 恩這個道理咱都懂, 連PCI都沒有,哪裡來的MSI啊。
反向依賴 select
這個關鍵字表示了當本配置項選中後,其他的配置項也需要選中
在 arch/x86/Kconfig文件中
config HIGHMEM64G
    bool "64GB"
    depends on !M386 && !M486
    select X86_PAE
    ---help---
      Select this if you have a 32-bit processor and more than 4
      gigabytes of physical RAM.

其實這個我也不懂,看上去就是說要支持更多的物理內存,那麼x86的平台上,就要X86_PAE
看上去是這麼回事兒。

革命尚未成功,同志仍需努力
好了,我要記錄的東西就到這裡了。突然這麼嘎然而止,估計大家一定意猶未盡
但是事實就是這樣,基本kconfig語法大家可以在 Document/kbuild/kconfig-language.txt中找到
就不用我在這裡搬出來照抄了。

kernel模塊之間的關聯又怎能是我這樣的初學者所能理解,不能理解又豈能講得清楚
這裡只是給大家一個入口,讓大家能夠進一步kernel的海洋中探索。話說,授之以魚不如授之以漁嘛
要讓linux kernel更好的發揮作用,讓更多的人參與這個項目,幫助更多的人,還有很長的路要走
革命尚未成功,同志仍需努力。

[轉] MTK6577+Android編譯之preloader

http://blog.csdn.net/loongembedded/article/details/38706537