Dalvik vm make file config and source tree

原创 2012年03月24日 21:01:25

Dalvik 虚拟机编译脚本 和 源代码树


本文简单的分析Dalvik虚拟机源码(dalvik/vm)的结构以及编译脚本(*.mk)

编译脚本

Dalvik源码目录结构并不复杂。其编译脚本也很简单。主要有以下几个文件组成:

dalvik/vm/Android.mk 

dalvik/vm/ReconfigureDvm.mk

dalvik/vm/Dvm.mk


和android系统里其他的模块类似,dalvik也是以Android.mk作为顶层编译配置文件或者入口。它的内容如下所示:

https://github.com/android/platform_dalvik/blob/master/vm/Android.mk


我们从头分析一下。首次按是注释说明:

#
# Android.mk for Dalvik VM.
#
# This makefile builds both for host and target, and so the very large
# swath of common definitions are factored out into a separate file to
# minimize duplication.
#
# If you enable or disable optional features here (or in Dvm.mk),
# rebuild the VM with:
#
#  make clean-libdvm clean-libdvm_assert clean-libdvm_sv clean-libdvm_interp
#  make -j4 libdvm
#

他告诉我们,该编译文件把dalvik编程成两部分,宿主机和目标机。对多数典型的配置下,宿主机就是我们的Linux编译服务器。而目标机就是我们的移动设备。 为了减少重复,宿主机和目标机都需要的编译配置被放到单独的文件里。单独的文件就是后面要讲道德(ReconfigureDvm.mk和Dvm.mk)。

同时,它也该出了在我们修改了dalvik源码后,怎么从头编译一个干净的实现出来。后面我们会动手实践。

LOCAL_PATH:= $(call my-dir)
和多数模块一样,接下来把dalvik源码路径赋值给LOCAL_PATH变量。以方便后面使用。这里LOCAL_PATH应该就是 dalvik/vm.

#
# Build for the target (device).
#

ifeq ($(TARGET_CPU_SMP),true)
    target_smp_flag := -DANDROID_SMP=1
else
    target_smp_flag := -DANDROID_SMP=0
endif
host_smp_flag := -DANDROID_SMP=1

# Build the installed version (libdvm.so) first
include $(LOCAL_PATH)/ReconfigureDvm.mk

# Overwrite default settings
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := libdvm
LOCAL_CFLAGS += $(target_smp_flag)
include $(BUILD_SHARED_LIBRARY)
首先为目标机编译。首先是根据目标机是否支持SMP,设置变量target_smp_flag。后面我们会看到该变量被用来传给编译器选项。而宿主机上现在绝大多数都是支持SMP的,所以就直接复制是指为支持。

紧接着就调用脚本ReconfigureDvm.mk,从名字我们不难猜出改脚本是用来为dvm编译初始化编译环境的。后面我们会看到它的主要内容。

下面接着就是现实dvm在宿主机上最终会被编译的目标了。这是一个共享库。名字叫libdvm。我们可以在编译好的机器上找到他

out/target/xxx/libs/libdvm.so

# If WITH_JIT is configured, build multiple versions of libdvm.so to facilitate
# correctness/performance bugs triage
ifeq ($(WITH_JIT),true)

    # Derivation #1
    # Enable assert and JIT tuning
    include $(LOCAL_PATH)/ReconfigureDvm.mk

    # Enable assertions and JIT-tuning
    LOCAL_CFLAGS += -UNDEBUG -DDEBUG=1 -DLOG_NDEBUG=1 -DWITH_DALVIK_ASSERT \
                    -DWITH_JIT_TUNING $(target_smp_flag)
    LOCAL_MODULE := libdvm_assert
    include $(BUILD_SHARED_LIBRARY)

    # Derivation #2
    # Enable assert and self-verification
    include $(LOCAL_PATH)/ReconfigureDvm.mk

    # Enable assertions and JIT self-verification
    LOCAL_CFLAGS += -UNDEBUG -DDEBUG=1 -DLOG_NDEBUG=1 -DWITH_DALVIK_ASSERT \
                    -DWITH_SELF_VERIFICATION $(target_smp_flag)
    LOCAL_MODULE := libdvm_sv
    include $(BUILD_SHARED_LIBRARY)

    # Derivation #3
    # Compile out the JIT
    WITH_JIT := false
    include $(LOCAL_PATH)/ReconfigureDvm.mk

    LOCAL_CFLAGS += $(target_smp_flag)
    LOCAL_MODULE := libdvm_interp
    include $(BUILD_SHARED_LIBRARY)

endif
这一部分是为JIT特有 的。当系统支持JIT编译器是,dvm会编译三个额外的目标共享库,用于支持dvm的开发特性。他们分别是

libdvm_assert 用来打开dvm源码中的断言(assert)。我们在后面的分析文章中会看到,dvm实现中大量使用断言来增加运行时的检查。当打开这些断言是,任何断言检查失败都将直接导致dvm异常退出。我们从trace file就能够找到那个断言失败,从而检查出可能存在的bug。在最终发布版本中,断言会被关闭,哪些断言相当于空语句。因而不会再最终发布版本中是dvm异常退出。

libdvm_sv 除了代开断言外,还带开了自我检查能力,用来在某些重要时刻检查当前dvm状态没有异常。我们在后面的文章里会详细分析dvm到底做了哪些自我检查。

最后一个版本 libdvm_interp 用来关掉JIT,而编译出一个纯解释器实现的dvm实例。这样子我们就可以检查打开JIT后行为有没有出现和解释器实现的dvm有行为差异。

我们可以在如下目录里找到这三个为调试生成的dvm共享库:

out/target/xxx/symbol/libs/


最后的内容是用来为宿主机编译的。所有的内容包裹在如下代码里:

#
# Build for the host.
#

ifeq ($(WITH_HOST_DALVIK),true)

...
endif

首先是清空本地变量内容:

    include $(CLEAR_VARS)

然后是根据编译环境设置三个编译变量:

    # Variables used in the included Dvm.mk.
    dvm_os := $(HOST_OS)
    dvm_arch := $(HOST_ARCH)
    # Note: HOST_ARCH_VARIANT isn't defined.
    dvm_arch_variant := $(HOST_ARCH)

这三个变量最终会传给编译器。它们会引入平台特有的行为。 由于宿主机不必支持JIT,所以将它设置为false。

WITH_JIT := false
include $(LOCAL_PATH)/Dvm.mk
Dvm.mk我们后面会接着分析。

接下来根据目标平台,有选择性的引入编译需要的库:

    LOCAL_SHARED_LIBRARIES += libcrypto libssl libicuuc libicui18n

    LOCAL_LDLIBS := -lpthread -ldl
    ifeq ($(HOST_OS),linux)
      # need this for clock_gettime() in profiling
      LOCAL_LDLIBS += -lrt
    endif

    # Build as a WHOLE static library so dependencies are available at link
    # time. When building this target as a regular static library, certain
    # dependencies like expat are not found by the linker.
    LOCAL_WHOLE_STATIC_LIBRARIES += libexpat libcutils libdex liblog libnativehelper libz

    # The libffi from the source tree should never be used by host builds.
    # The recommendation is that host builds should always either
    # have sufficient custom code so that libffi isn't needed at all,
    # or they should use the platform's provided libffi. So, if the common
    # build rules decided to include it, axe it back out here.
    ifneq (,$(findstring libffi,$(LOCAL_SHARED_LIBRARIES)))
        LOCAL_SHARED_LIBRARIES := \
            $(patsubst libffi, ,$(LOCAL_SHARED_LIBRARIES))
    endif

最后告诉编译系统,dvm在宿主机上的编译结果有两个:

LOCAL_CFLAGS += $(host_smp_flag)
    LOCAL_MODULE_TAGS := optional
    LOCAL_MODULE := libdvm

    include $(BUILD_HOST_SHARED_LIBRARY)

    # Copy the dalvik shell script to the host's bin directory
    include $(CLEAR_VARS)
    LOCAL_IS_HOST_MODULE := true
    LOCAL_MODULE_TAGS := optional
    LOCAL_MODULE_CLASS := EXECUTABLES
    LOCAL_MODULE := dalvik
    include $(BUILD_SYSTEM)/base_rules.mk
$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/dalvik | $(ACP)
	@echo "Copy: $(PRIVATE_MODULE) ($@)"
	$(copy-file-to-new-target)
	$(hide) chmod 755 $@

它们分别是 dvm共享库libdvm.so 和可执行文件dalvikvm。我们编译后的目录里能找到它们:

out/host/xxx/libs/libdvm.so

out/host/xxx/bin/dalvikvm


前面我们看到,dvm在目标机上编译的结果可能有好几个,最终的共享库libdvm.so,以及几个开发使用的共享库libsdvm_xx.so。编译这些目标是我们需要首先清理当前的编译环境,以排除编译前一个目标多带来的副作用。这个工作单独放到编译脚本ReconfigureDvm.mk,以减少重复。ReconfigureDvm.mk内容如下:


include $(CLEAR_VARS)

# Variables used in the included Dvm.mk.
dvm_os := $(TARGET_OS)
dvm_arch := $(TARGET_ARCH)
dvm_arch_variant := $(TARGET_ARCH_VARIANT)

# for now, disable x86-atom variant
ifeq ($(dvm_arch_variant),x86-atom)
dvm_arch_variant := x86
endif

include $(LOCAL_PATH)/Dvm.mk

LOCAL_SHARED_LIBRARIES += liblog libcutils libnativehelper libz libdl

LOCAL_STATIC_LIBRARIES += libdex

LOCAL_C_INCLUDES += external/stlport/stlport bionic/ bionic/libstdc++/include
LOCAL_SHARED_LIBRARIES += libstlport

# Don't install on any build by default
LOCAL_MODULE_TAGS := optional

它的内容也不出意外。清除本地变量,设置dvm变量,引入dvm需要的库。最后设置LOCAL_MODULE_TAGS为optional来告诉编译系统除非显式指明(include dalvik/vm/android.mk),否则不会编译dvm。


最后一个文件dvm.mk设置了宿主机和目标机都需要的定义。其内容也很直观。完整的内容如下:

https://github.com/android/platform_dalvik/blob/master/vm/Dvm.mk

首先是设置编译器选项:

#
# Compiler defines.
#
LOCAL_CFLAGS += -fstrict-aliasing -Wstrict-aliasing=2 -fno-align-jumps
LOCAL_CFLAGS += -Wall -Wextra -Wno-unused-parameter
LOCAL_CFLAGS += -DARCH_VARIANT=\"$(dvm_arch_variant)\"

接着判断编译时有没有指定DEBUG_DALVIK_VM:

#
# Optional features.  These may impact the size or performance of the VM.
#

# Make a debugging version when building the simulator (if not told
# otherwise) and when explicitly asked.
dvm_make_debug_vm := false
ifneq ($(strip $(DEBUG_DALVIK_VM)),)
  dvm_make_debug_vm := $(DEBUG_DALVIK_VM)
endif

如果指定了该选项,则打开额外的编译选项,否则什么都不多做:

ifeq ($(dvm_make_debug_vm),true)
  #
  # "Debug" profile:
  # - debugger enabled
  # - profiling enabled
  # - tracked-reference verification enabled
  # - allocation limits enabled
  # - GDB helpers enabled
  # - LOGV
  # - assert()
  #
  LOCAL_CFLAGS += -DWITH_INSTR_CHECKS
  LOCAL_CFLAGS += -DWITH_EXTRA_OBJECT_VALIDATION
  LOCAL_CFLAGS += -DWITH_TRACKREF_CHECKS
  LOCAL_CFLAGS += -DWITH_EXTRA_GC_CHECKS=1
  #LOCAL_CFLAGS += -DCHECK_MUTEX
  LOCAL_CFLAGS += -DDVM_SHOW_EXCEPTION=3
  # add some extra stuff to make it easier to examine with GDB
  LOCAL_CFLAGS += -DEASY_GDB
  # overall config may be for a "release" build, so reconfigure these
  LOCAL_CFLAGS += -UNDEBUG -DDEBUG=1 -DLOG_NDEBUG=1 -DWITH_DALVIK_ASSERT
else  # !dvm_make_debug_vm
  #
  # "Performance" profile:
  # - all development features disabled
  # - compiler optimizations enabled (redundant for "release" builds)
  # - (debugging and profiling still enabled)
  #
  #LOCAL_CFLAGS += -DNDEBUG -DLOG_NDEBUG=1
  # "-O2" is redundant for device (release) but useful for sim (debug)
  #LOCAL_CFLAGS += -O2 -Winline
  #LOCAL_CFLAGS += -DWITH_EXTRA_OBJECT_VALIDATION
  LOCAL_CFLAGS += -DDVM_SHOW_EXCEPTION=1
  # if you want to try with assertions on the device, add:
  #LOCAL_CFLAGS += -UNDEBUG -DDEBUG=1 -DLOG_NDEBUG=1 -DWITH_DALVIK_ASSERT
endif  # !dvm_make_debug_vm

紧接着是该文件的大头,引入编译源文件。其中包括 所有平台都会使用到的源文件,如 AllocTracker.cpp等。为支持JIT特有的文件,如compiler/Compiler.cpp等。其中以下部分特别需要我们关注:

ifeq ($(WITH_COPYING_GC),true)
  LOCAL_CFLAGS += -DWITH_COPYING_GC
  LOCAL_SRC_FILES += \
	alloc/Copying.cpp.arm
else
  LOCAL_SRC_FILES += \
	alloc/HeapSource.cpp \
	alloc/MarkSweep.cpp.arm
endif

这是在指定垃圾收集器的类型。当在编译选项中指定WITH_COPYING_GC后就使用拷贝垃圾收集器,否则就是用标记-清除垃圾收集器。我们后面会在单独的章节里介绍dvm垃圾收集。

至此编译脚本的解析全部完成。dvm源代码结构简单,其编译脚本也很清晰。


源码目录树

下面是dvm源码目录树。后面章节会分别介绍其中最重要的部分:

https://github.com/android/platform_dalvik/tree/master/vm


dalvik VM的解释器分析

以KK的dalvik源码为基础来解析。 使用的源码基于https://github.com/AOKP/dalvik, 可以从https://github.com/AOKP/dalvik/archive...
  • doon
  • doon
  • 2016年07月25日 17:29
  • 1714

android 4.2.1 下载和编译

本人安装的是ubuntu12.04 64位系统 1、mkdir ~/bin PATH=~/bin:$PATH 2、curl https://dl-ssl.google.com/dl/googlesou...
  • firekylin_2000
  • firekylin_2000
  • 2013年01月01日 14:36
  • 2685

Go support for Android

Abstract We propose to introduce Go support for the Android platform. The focus will be on su...
  • rznice
  • rznice
  • 2014年12月17日 20:43
  • 1006

Android7.0 编译系统流程分析

本文按照Android编译三部曲(source,lunch和make)的步骤来分析查看每个环节的主要流程,由于编译系统太过庞大,这里只是从关键的主干流程上做一个分析,不可能做到每个细节都剖析清楚,由于...
  • lizekun2010
  • lizekun2010
  • 2016年09月20日 17:26
  • 5065

深入理解Android之Java虚拟机Dalvik

一、背景这个选题很大,但并不是一开始就有这么高大上的追求。最初之时,只是源于对Xposed的好奇。Xposed几乎是定制ROM的神器软件技术架构或者说方法了。它到底是怎么实现呢?我本意就是想搞明白Xp...
  • Innost
  • Innost
  • 2015年12月22日 09:55
  • 32521

Dalvik虚拟机的启动过程分析

在Android系统中,应用程序进程都是由Zygote进程孵化出来的,而Zygote进程是由Init进程启动的。Zygote进程在启动时会创建一个Dalvik虚拟机实例,每当它孵化一个新的应用程序进程...
  • Luoshengyang
  • Luoshengyang
  • 2013年05月13日 00:57
  • 63800

Android开发如何定制framework层服务

刚刚跨完年,新年第一篇文章,那么今天将对Android开发framework中间层的服务定制使用作个总结。首先我们先导入Android平台源码framework层的代码到开发工具eclipse中,代码...
  • u013171283
  • u013171283
  • 2018年01月02日 17:12
  • 148

dalvik核心数据结构

JavaVM, JNIEnv typedef const struct JNINativeInterface* JNIEnv; typedef const struct JNIInvokeInter...
  • ericming200409
  • ericming200409
  • 2015年05月08日 12:03
  • 1919

Dalvik控制VM详解

1.扩展的JNI检测      JNI(Java native Interface)是Java本地接口,提供了Java语言程序调用本地(C/C++)代码的方法。为了能触发CheckJNI标志位,第二...
  • CodeMyDream
  • CodeMyDream
  • 2016年12月23日 14:26
  • 499

source Tree 基本操作

内容提交提交方法一:1.解决工作副本冲突; 点击 工作副本,将“未暂存文件”中,非自己修改的内容进行 reset 或者 移除等操作,防止该文件对自己所要上传内容造成冲突 2.拉去远端; 点击菜单...
  • u011484013
  • u011484013
  • 2017年05月04日 18:51
  • 966
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Dalvik vm make file config and source tree
举报原因:
原因补充:

(最多只允许输入30个字)