2011-10-15 16:59:08

 

2011-10-15 16:59:08


這個函數做了兩件事情,一是在主線程中創建了一個ActivityThread實例,二是通過Looper類使主線程進入消息循環中,這裏我們只關注後者。

首先看Looper.prepareMainLooper函數的實現,這是一個靜態成員函數,定義在frameworks/base/core/java/android/os/Looper.java文件中:

public class Looper {
 ......

 private static final ThreadLocal sThreadLocal = new ThreadLocal();

 final MessageQueue mQueue;

 ......

 /** Initialize the current thread as a looper.
 * This gives you a chance to create handlers that then reference
 * this looper, before actually starting the loop. Be sure to call
 * {@link #loop()} after calling this method, and end it by calling
 * {@link #quit()}.
 */
 public static final void prepare() {
  if (sThreadLocal.get() != null) {
   throw new RuntimeException("Only one Looper may be created per thread");
  }
  sThreadLocal.set(new Looper());
 }

 /** Initialize the current thread as a looper, marking it as an application's main
 *  looper. The main looper for your application is created by the Android environment,
 *  so you should never need to call this function yourself.
 * {@link #prepare()}
 */

 public static final void prepareMainLooper() {
  prepare();
  setMainLooper(myLooper());
  if (Process.supportsProcesses()) {
   myLooper().mQueue.mQuitAllowed = false;
  }
 }

 private synchronized static void setMainLooper(Looper looper) {
  mMainLooper = looper;
 }

 /**
 * Return the Looper object associated with the current thread.  Returns
 * null if the calling thread is not associated with a Looper.
 */
 public static final Looper myLooper() {
  return (Looper)sThreadLocal.get();
 }

 private Looper() {
  mQueue = new MessageQueue();
  mRun = true;
  mThread = Thread.currentThread();
 }

 ......
}       

函數prepareMainLooper做的事情其實就是在線程中創建一個Looper對象,這個Looper對象是存放在sThreadLocal成員變量裏面的,成員變量sThreadLocal的類型爲ThreadLocal,

表示這是一個線程局部變量,即保證每一個調用了prepareMainLooper函數的線程裏面都有一個獨立的Looper對象。

在線程是創建Looper對象的工作是由prepare函數來完成的,而在創建Looper對象的時候,會同時創建一個消息隊列MessageQueue,

保存在Looper的成員變量mQueue中,後續消息就是存放在這個隊列中去。消息隊列在Android應用程序消息處理機制中最重要的組件,因此,我們看看它的創建過程,

即它的構造函數的實現,實現frameworks/base/core/java/android/os/MessageQueue.java文件中:


view plaincopy to clipboardprint?
01.public class MessageQueue { 
02.    ...... 
03. 
04.    private int mPtr; // used by native code  
05. 
06.    private native void nativeInit(); 
07. 
08.    MessageQueue() { 
09.        nativeInit(); 
10.    } 
11. 
12.    ...... 
13.} 
public class MessageQueue {
 ......

 private int mPtr; // used by native code

 private native void nativeInit();

 MessageQueue() {
  nativeInit();
 }

 ......
}        它的初始化工作都交給JNI方法nativeInit來實現了,這個JNI方法定義在frameworks/base/core/jni/android_os_MessageQueue.cpp文件中:


view plaincopy to clipboardprint?
01.static void android_os_MessageQueue_nativeInit(JNIEnv* env, jobject obj) { 
02.    NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue(); 
03.    if (! nativeMessageQueue) { 
04.        jniThrowRuntimeException(env, "Unable to allocate native queue"); 
05.        return; 
06.    } 
07. 
08.    android_os_MessageQueue_setNativeMessageQueue(env, obj, nativeMessageQueue); 
09.} 
static void android_os_MessageQueue_nativeInit(JNIEnv* env, jobject obj) {
    NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
    if (! nativeMessageQueue) {
        jniThrowRuntimeException(env, "Unable to allocate native queue");
        return;
    }

    android_os_MessageQueue_setNativeMessageQueue(env, obj, nativeMessageQueue);
}       

在JNI中,也相應地創建了一個消息隊列NativeMessageQueue,NativeMessageQueue類也是定義在frameworks/base/core/jni/android_os_MessageQueue.cpp文件中,

它的創建過程如下所示:


view plaincopy to clipboardprint?
01.NativeMessageQueue::NativeMessageQueue() { 
02.    mLooper = Looper::getForThread(); 
03.    if (mLooper == NULL) { 
04.        mLooper = new Looper(false); 
05.        Looper::setForThread(mLooper); 
06.    } 
07.} 
NativeMessageQueue::NativeMessageQueue() {
    mLooper = Looper::getForThread();
    if (mLooper == NULL) {
        mLooper = new Looper(false);
        Looper::setForThread(mLooper);
    }
}   


static JNINativeMethod gMessageQueueMethods[] = {
    /* name, signature, funcPtr */
    { "nativeInit", "()V", (void*)android_os_MessageQueue_nativeInit },
    { "nativeDestroy", "()V", (void*)android_os_MessageQueue_nativeDestroy },
    { "nativePollOnce", "(II)V", (void*)android_os_MessageQueue_nativePollOnce },
    { "nativeWake", "(I)V", (void*)android_os_MessageQueue_nativeWake }
};

MessageQueue  的創建

static void android_os_MessageQueue_nativeInit(JNIEnv* env, jobject obj) {
    NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
    if (! nativeMessageQueue) {
        jniThrowRuntimeException(env, "Unable to allocate native queue");
        return;
    }

    android_os_MessageQueue_setNativeMessageQueue(env, obj, nativeMessageQueue);
}

創建了一個線程

export CROSS_COMPILE=~/myandroid/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi-

 cd ~/myandroid/bootable/bootloader/uboot-imx
   
    $ export ARCH=arm
    $ export CROSS_COMPILE=~/myandroid/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi-

    Command to build for i.MX51 BBG board is:
    $ make distclean
    $ make mx51_bbg_android_config
    $ make

    Command to build for i.MX53 TABLET board is:
    $ make distclean
    $ make mx53_smd_android_config
    $ make

 


    Command to build for i.MX53 ARD board is:
    $ make distclean
    $ make mx53_ard_config  (If your board has DDR3, then using mx53_ard_ddr3_config)
    $ make

 


    Command to build for i.MX50 RD3 board is:
    $ make distclean
    $ make mx50_rd3_android_config
    $ make

    "u-boot.bin" is generated if you have a successful build.

    The above u-boot.bin has 1024KB padding at the head of file,for example first executable instruction is at the offset 1KB. If you want to generate a no-padding image, you need do below dd command in host.
    $ sudo dd if=./u-boot.bin of=./u-boot-no-padding.bin bs=1024 skip=1; sync
    
    Usually this no-padding uboot image is used in the SD card, for example, program this no-padding uboot image into 1KB offset of SD card so that we do not overwrite the MBR (including partition table) within first 512B on the SD card.

    Note: Any image which must be loaded by uboot must have an unique image head, for example, some data must be added at the head of loaded image to tell uboot about the image (for example, it's a kernel, or ramfs, etc) and how to load the image (for example, load/execute address).
    Therefor before you can load any image into RAM by uboot, you need a tool to add this information to generate a new image which can be recognized by uboot. Fortunately, this tool is delivered together with uboot. After you make uboot using the above steps, you can find the tool (mkimage) under tools/.
    Later the document will describe how to use mkimage to generate the image (for example kernel image, ramfs image) to be loaded by uboot. 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章