1. 程式人生 > >Android上層啟動過程的幾個關鍵點

Android上層啟動過程的幾個關鍵點

        現在在工程中遇到了實際的問題,反過來閱讀下程式碼,再重新審視一下在kernel啟動之後的ANDROID啟動過程。

        在frameworks/base/services/java/com/android/server資料夾下的SystemServer.cpp檔案。在此檔案中呼叫了init1()函式,檔案中對次函式的描述為:這個方法是從Zygote中呼叫來初始化系統。這將引起本地的服務(Surfaceflinger,audioflinger等)開啟。在這些完成之後將回調init2()來開始android服務。

       從上面的描述中我們可以得知兩個方面:一是在android的服務中,我們分兩種服務,一種是native服務,另一種是android服務。二是我們的本地服務是在init1()的過程中完成的,而android服務是在init2()的過程中完成的。

        從實際的真機的啟動過程的列印資訊我們也能夠看出,在啟動的過程中,我們首先會啟動SurfaceFlinger,AudioFlinger然後開始啟動dalikvm,從而進入對Zygote和System並且通過呼叫system_init()函式和sysproc來啟動Android runtime 啟動native service。通過回撥init2(),Android  service\thread pool從而進入systemserver,執行systemserver執行緒,將註冊到systemserver中的服務啟動。

        如果我們想借助Android本身的架構來完成新增我們的服務的目的的情況下我們不妨就利用這些。

        在我們通過使用JNI機制使得上層的java應用能夠呼叫native service。而具體的實現就是將.cpp檔案放在JNI資料夾下,而將.java檔案放在java資料夾下。具體步驟如下:

        在上文中,我們說過我們可以藉助Android自身架構的東西來完成我們的JNI服務,而不必每個細節都自己完成。並且我們提到我們會呼叫AndroidRuntime所以我們可以將服務註冊到AndroidRuntime.cpp檔案中。下面是個經典的例子,此處做個摘抄地址為http://dongyulong.blog.51cto.com/1451604/545496(但是不知道是不是原作者)

frameworks/base/core/jni 路徑下建立例子 android_mytest_hellojni.cpp

 檔案,這個檔案就是在 JNI 層實現介面。檔案內容如下:(可參考同一目錄下的 android_debug_JNITest.cpp 檔案編寫)

#define LOG_TAG "HelloJNI"
#include "jni.h"
#include "nativehelper/JNIHelp.h"
#include "utils/Log.h"
#include "utils/misc.h"

namespace android {
static jstring android_mytest_hellojni_displayString(JNIEnv *env, jclass clazz)
{
 return env->NewStringUTF("Hello from JNI!");
} 

/*
 * JNI registration.
 */

static JNINativeMethod gMethods[] = {
    /* name, signature, funcPtr */
    { "displayString", "()Ljava/lang/String;",
            (void*) android_mytest_hellojni_displayString },
    
};
int register_android_mytest_hellojni(JNIEnv* env)
{ //此處的目錄結構就是在Javaframework層的檔案目錄,且必須一致

return jniRegisterNativeMethods(env, "android/mytest/hellojni", 
        gMethods, NELEM(gMethods));
}
};

2. JNI 層:對編譯的修改配置

  2.1修改/Android/android-1.6_r2/frameworks/base/core/jni目錄下的Android.mk 檔案,在LOCAL_SRC_FILES:= \ 下面加上
android_mytest_hellojni.cpp \ 
   2.2修改/Android/android-1.6_r2/frameworks/base/core/jni目錄下的AndroidRuntime.cpp 檔案在extern int 後面新增
extern int register_android_mytest_hellojni(JNIEnv* env); 
然後在static const RegJNIRec gRegJNI[] = {下面新增
REG_JNI(register_android_mytest_hellojni), 
這樣,JNI層的修改就到此為止了。

frameworks/base/core/java/android/ 新建檔案目錄 mytest ,在該目錄下新建檔案 hellojni.java 宣告介面。內容如下:(可以參考 android-1.6_r2/frameworks/base/core/java/android/debug 目錄下的 JNITest.java 檔案編寫) 

package android.mytest;
public class hellojni{
    public hellojni(){}
//此處宣告為public所以才可以被application呼叫

    public static native String displayString(); 
}

4 .下面我們要對我們做過更改的 libandroid_runtime.so 和 framework.jar 進行重新編譯。

在原始碼工程目錄下輸入 make libandroid_runtime 重新編譯生成 libandroid_runtime.so

target thumb C++: libandroid_runtime <= frameworks/base/core/jni/android_mytest_hellojni.cpp

target thumb C++: libandroid_runtime <= frameworks/base/core/jni/AndroidRuntime.cpp

target SharedLib: libandroid_runtime (out/target/product/generic/obj/SHARED_LIBRARIES/libandroid_runtime_intermediates/LINKED/libandroid_runtime.so)

target Prelink: libandroid_runtime (out/target/product/generic/symbols/system/lib/libandroid_runtime.so)

target Strip: libandroid_runtime (out/target/product/generic/obj/lib/libandroid_runtime.so)

Install: out/target/product/generic/system/lib/libandroid_runtime.so

然後再輸入 make framework 重新編譯生成 framework.jar

Install: out/target/product/generic/system/framework/framework.jar