2011-10-15 16:59:08

来源:互联网 发布:g92 l双头螺纹编程 编辑:程序博客网 时间:2024/04/27 01:57
 

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.