在之前的博文中《Android源碼學習之如何創建使用JNI》和《Android源碼學習之如何使用eclipse+NDK》中,淺談了如何創建使用JNI和如何利用NDK工具開發創建和lib**.so(Windows下)庫和調用Naive函數,做了這些工作只有一個目的,就是因為Android源碼中“大量”的使用到Native,所以了解一些Native語言和Java如何與Native互通,對分析Android源碼還是有很大的幫助的(好像廢話很多~~~)。
本人通過對SystemServer源碼進行淺析,看它是如何設計的。
首先利用Source Insight工具搜索到SystemServer.java代碼,找到入口函數main(),代碼如下:
native public static void init1(String[] args); public static void main(String[] args) { if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) { // If a device's clock is before 1970 (before 0), a lot of // APIs crash dealing with negative numbers, notably // java.io.File#setLastModified, so instead we fake it and // hope that time from cell towers or NTP fixes it // shortly. Slog.w(TAG, "System clock is before 1970; setting to 1970."); SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME); } if (SamplingProfilerIntegration.isEnabled()) { SamplingProfilerIntegration.start(); timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { SamplingProfilerIntegration.writeSnapshot("system_server", null); } }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL); } // Mmmmmm... more memory! dalvik.system.VMRuntime.getRuntime().clearGrowthLimit(); // The system server has to run all of the time, so it needs to be // as efficient as possible with its memory usage. VMRuntime.getRuntime().setTargetHeapUtilization(0.8f); System.loadLibrary("android_servers"); init1(args); } public static final void init2() { Slog.i(TAG, "Entered the Android system server!"); Thread thr = new ServerThread(); thr.setName("android.server.ServerThread"); thr.start(); }
在main函數最后兩行代碼System.loadLibrary("android_servers");和init1(args);還有第一行代碼native public static void init1(String[] args);要是理解了本人之前的兩篇博文的,對這三行代碼也太熟悉了,就是首先加載動態庫libandroid_servers.so,然后調用native的init1()函數。接着往下走,看看native函數init1()是什么樣子的(注:記得這里的init2()函數,一會兒在native層函數中會調用到這個函數)。
首先如何找到該init1()函數?通過之前的博文,我們知道在調用native函數所在的類與native編寫的類進行溝通,是通過“類名”的相似性或者是在Android.mk文件中定義,所以根據這條思路我們知道該java類的包名為package com.android.server;以及類名為“SystemServer”,所以將它們的"."改成"_"組合為“com_android_server_SystemServer”,這樣通過source insight搜索有沒有這個文件,終於找到了,並且可以找到調用的nitive函數init()。代碼如下:
/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <utils/Log.h> #include <utils/misc.h> #include "jni.h" #include "JNIHelp.h" namespace android { extern "C" int system_init(); static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz) { system_init(); } /* * JNI registration. */ static JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "init1", "([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1 }, }; int register_android_server_SystemServer(JNIEnv* env) { return jniRegisterNativeMethods(env, "com/android/server/SystemServer", gMethods, NELEM(gMethods)); } }; // namespace android
整個文件就這么幾行代碼,比較簡單。目前只關心Native函數android_server_SystemServer_init1(JNIEnv* env, jobject clazz),它是調用上面那個用extern聲明的一個外部system_init函數。接着搜索這個函數所在的文件,這個函數是在另外一個庫libsystem_server.so中實現,找到類System_init.cpp后,可以看到函數system_init(),代碼如下:
extern "C" status_t system_init() { LOGI("Entered system_init()"); sp<ProcessState> proc(ProcessState::self()); sp<IServiceManager> sm = defaultServiceManager(); LOGI("ServiceManager: %p\n", sm.get()); sp<GrimReaper> grim = new GrimReaper(); sm->asBinder()->linkToDeath(grim, grim.get(), 0); char propBuf[PROPERTY_VALUE_MAX]; property_get("system_init.startsurfaceflinger", propBuf, "1"); if (strcmp(propBuf, "1") == 0) { // Start the SurfaceFlinger SurfaceFlinger::instantiate(); } property_get("system_init.startsensorservice", propBuf, "1"); if (strcmp(propBuf, "1") == 0) { // Start the sensor service SensorService::instantiate(); } // And now start the Android runtime. We have to do this bit // of nastiness because the Android runtime initialization requires // some of the core system services to already be started. // All other servers should just start the Android runtime at // the beginning of their processes's main(), before calling // the init function. LOGI("System server: starting Android runtime.\n"); AndroidRuntime* runtime = AndroidRuntime::getRuntime(); LOGI("System server: starting Android services.\n"); JNIEnv* env = runtime->getJNIEnv(); if (env == NULL) { return UNKNOWN_ERROR; } jclass clazz = env->FindClass("com/android/server/SystemServer"); if (clazz == NULL) { return UNKNOWN_ERROR; } jmethodID methodId = env->GetStaticMethodID(clazz, "init2", "()V"); if (methodId == NULL) { return UNKNOWN_ERROR; } env->CallStaticVoidMethod(clazz, methodId); LOGI("System server: entering thread pool.\n"); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); LOGI("System server: exiting thread pool.\n"); return NO_ERROR; }
函數具體要做什么,有什么功能我們暫且不考慮,我們找到我們關系的幾行代碼:
jclass clazz = env->FindClass("com/android/server/SystemServer");
if (clazz == NULL) {
return UNKNOWN_ERROR;
}
jmethodID methodId = env->GetStaticMethodID(clazz, "init2", "()V");
if (methodId == NULL) {
return UNKNOWN_ERROR;
}
env->CallStaticVoidMethod(clazz, methodId);
這幾行代碼我們熟~~~,是通過“com/android/server/SystemServer”找到類,這個類不就是我們本博文開篇的SystemServer.java的類嗎。找到類對象后,再調用該對象的init2函數,然后執行init2()函數,我們在溫習下init2()函數,代碼如下:
public static final void init2() {
Slog.i(TAG, "Entered the Android system server!");
Thread thr = new ServerThread(); thr.setName("android.server.ServerThread");
thr.start();
}
總結:我們放開代碼的功能不說,單純的從java和nitive的交互和相互調用上說,通過之前的學習,對於理解Android源碼的脈絡是有幫助的,只有在了解了整個Android源碼的脈絡和一些Android源碼組織的框架架構,對理解整個源碼是更加輕松的。
記錄下自己的學習過程,為己為人,內容膚淺,請高手多多指導~~~