在之前的博文中《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() {@Overridepublic 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源码组织的框架架构,对理解整个源码是更加轻松的。

记录下自己的学习过程,为己为人,内容肤浅,请高手多多指导~~~

转载于:https://www.cnblogs.com/yemeishu/archive/2012/12/26/2833415.html

Android源码学习之浅析SystemServer脉络相关推荐

  1. 【Android 源码学习】SystemServer启动原理

    Android 源码学习 SystemServer启动原理 望舒课堂 SystemServer进程启动原理学习记录整理. 参考文章: Android系统启动流程(三)解析SyetemServer进程启 ...

  2. 【Android 源码学习】Zygote启动原理

    Android 源码学习 Zygote启动原理 望舒课堂 Zygote进程启动原理学习记录整理. Zygote简介 Zygote是进程在init进程启动时创建的,进程本身是app_process,来源 ...

  3. android源码学习-Toast实现原理讲解

    前言: 前些日志QQ群有朋友发了一个Toast的崩溃日志.Toast如此简单的用法怎么会崩溃呢?所以顺便就学习了一下Toast在源码中的实现,不算复杂,但内容挺多的,这里就来分享一下,方便读者. 一. ...

  4. 【Android 源码学习】 init启动

    目录 Android 源码学习 init启动 从main.cpp开始 init.cpp 部分逻辑 init启动zygote 属性服务 总结 Android 源码学习 init启动 Android 11 ...

  5. 【Android 源码学习】系统架构和启动流程

    Android 源码学习 系统架构和启动流程 望舒课堂 学习记录整理.以及以下参考文章的整理汇总.便于我个人的学习记录. 感谢IngresGe,Gityuan的精彩文章.为我们这些初探android系 ...

  6. vuex commit 模块_长篇连载:Vuex源码学习(二)脉络梳理

    前车之鉴 有了vue-router源码学习的经验,每次看认真钻研源代码的时候都会抽出一小段时间来大体浏览一遍源代码.大体了解这个源代码的脉络,每个阶段做了什么,文件目录的划分.下面我来带大家梳理一下V ...

  7. 【Android 源码学习】SharedPreferences 源码学习

    第一章:SharedPreferences 源码学习 文章目录 第一章:SharedPreferences 源码学习 Android SharedPreferences的缺陷 MMKV.Jetpack ...

  8. Android源码学习之工厂方法模式应用

    主要内容: 工厂方法模式定义 工厂方法模式优势 工厂方法模式在Android源码中的应用 一.工厂方法模式定义 工厂方法模式定义: Define an interface for creating a ...

  9. Android源码学习之handler

    前言 是滴!我又来了...今天来讲讲老少皆宜的大名鼎鼎的handler.是的,想必handler这个东西已经被讨论的天花乱坠了,也经常被我们用在实际开发中,但是其中很多细节知识还是值得我们去学习深究的 ...

最新文章

  1. Java 内存泄漏排查,新技能+1
  2. 漫画:什么是 JVM 的垃圾回收?
  3. phpcms列表页调用 点击量
  4. python词云乱码_python词云库wordCloud使用方法详解(解决中文乱码)
  5. Ubuntu安装aira2及开机启动配置
  6. 荣耀20/20 Pro相机规格曝光:DxOMark排名或将再次改变
  7. .NET 6 Preview 4 已发布,这些新功能值得关注!
  8. 2019美赛备战任务
  9. win2012没有远程桌面授权服务器可以提供许可证 如何远程
  10. VIM教程与学习资料汇总(转载自善用佳软)
  11. php excel 下拉菜单,Yii2+phpexcel导出二级联动菜单
  12. python图片背景透明
  13. 金山词霸 for linux,在Linux下使用金山词霸2003
  14. 虚拟机里博图能连接上实物PLC,但是HMI仿真不能连接实物PLC
  15. Excel公式-文本查找函数
  16. java.lang.IllegalArgumentException: MALFORMED
  17. IM即时通讯系统优势,区块链社交APP如何搭建
  18. VR企业宣传满足宣传需求给客户强烈的真实感
  19. C++ nth_element 介绍
  20. 基于MATLAB的Kmeans聚类算法的仿真与分析

热门文章

  1. React怎样从函数中辨别类
  2. python成功之路,Day1-发展历史
  3. QT学习小结之信号与槽
  4. ASP.NET数据绑定控件数据项中的服务器控件注册JS方法
  5. 【DP + 卖股票】LeetCode 714. Best Time to Buy and Sell Stock with Transaction Fee
  6. Unable to access “***“, Failed to mount ‘/dev/sda7‘: Operation not permitted
  7. MySQL的ibdata1文件占用过大
  8. SFP光模块与SFP+、XFP、QSFP、GBIC、BIDI的区别
  9. Linux命令 ls -l s输出内容含义详解
  10. mysql中添加中文存储和显示功能