《深入解析Android5.0系统》 一书笔记

Android的Build系统非常的庞大,他是基于GUN Make以及shell来构建的,我们主要的面对方向是Android.mk文件,这也是Android为我们处理好的,不用直接跟shell打交道,Build不光可以处理系统的编译打包,还能生成img镜像等,十分的强大。

从大的方面来说,Build系统分为三大块,第一块处于build/core目录下的文件,这是Build的基础框架和核心部分,第二块处于device目录下的文件,存放的是项目的一些配置信息,第三块就是各大模块的Android.mk了。

我们本篇文章依葫芦画瓢的来侃侃Build,我也是跟着书上来的,我也不是很会C/C++

在说Build前,我简单带过一下,我们之前有教过通过SecureCRT远程连接Linux,我们现在用Xshell去连接

其实Xshell连接是非常简单的,我们只需要在ubuntu的终端输入ifconfig,来查看你的ip:比如我的ip是:192.111.11.11(假设)

那么我的Xshell只需要新建一个端口

但是如果连接失败,那你就要检查一下ssh了,在ubuntu的终端输入:

ps -e |grep ssh

如果没有反应,说明你的ssh没有安装

sudo apt install openssh-server

最后就可成功连接了

一.Build系统核心

我们进入build/core目录下,这个目录里有很多的mk文件以及shell脚本,perl脚本,我们跟踪一下源码的编译

source build/envsetup.sh
lunch
make 

我们顺着这三条命令来查看源码

1.envsetup.sh

这个脚本我们先来看看他的内容是什么,我们打开build/envsetup.sh,可以看到里面的脚本中,中间部分插入了lunch选择的参数列表,在结尾处,find了device和vendor目录下的vendorsetuo.sh文件,然后运行他们,我们找一下,看下是否有vendorsetuo.sh,在 device/lge/hammerhead/目录下可以看到有一个vendorsetuo.sh脚本

我们打开它你可以发现,它里面就一行代码

add_lunch_combo aosp_hammerhead-userdebug

它依旧调用add_lunch_combo函数,这样看来,envsetup.sh除了建立shell命令外,就是执行这一句命令了,我们来看下add_lunch_combo的定义:

add_lunch_combo命令的功能,是将调用这个命令所传递的参数放在一个全局的数组变量LUNCH_MENU_CHOICES中,执行lunch就是打印出这个数组的内容了,也就是我们上篇末尾所展示的样子,还记得吗?我选了5

envsetup.sh中还定义了一些实用的shell脚本

  • lunch:指定编译产品
  • tapas:以交互方式
  • croot:快速切换到源码的根目录
  • m:编译整个源码,可以不用切换到根目录
  • mm:编译当前目录下的源码,不包含他们的依赖模块
  • mmm:编译指定目录下的所有模块,不包含他们的依赖模块
  • mma:编译当前目录下的源码,包含他们的依赖模块
  • mmmma:编译指定目录下的所有模块,包含他们的依赖模块
  • cgrep:对系统下所有的C/C++执行grep命令
  • ggrep:对系统本地所有的Gradle执行grep命令
  • jgrep:对系统下所有的Java执行grep命令
  • resgrep:对系统下所有的res目录下的xml执行grep命令
  • sgrep:对系统下所有的源文件执行grep命令
  • godir:根据godir后的参数文件名在整个目录下查找,并且切换目录

2.lunch命令的功能

我们来看第二行代码lunch,这里我们分析下这个函数

function lunch()
{local answer# 如果lunch后面没有参数,那么打印菜单,并将选择值放入answer# 如果有参数,直接赋值if [ "$1" ] ; thenanswer=$1elseprint_lunch_menuecho -n "Which would you like? [aosp_arm-eng] "read answerfilocal selection=# 如果answer为空,则selection=aosp_arm-eng# 如果answer为数字并且小于或等于菜单数目,则把相应的菜单栏的数字赋值给他# 如果answer包含了一个-,则将answer赋值给selection,否则报错if [ -z "$answer" ]thenselection=aosp_arm-engelif (echo -n $answer | grep -q -e "^[0-9][0-9]*$")thenif [ $answer -le ${#LUNCH_MENU_CHOICES[@]} ]thenselection=${LUNCH_MENU_CHOICES[$(($answer-1))]}fielif (echo -n $answer | grep -q -e "^[^\-][^\-]*-[^\-][^\-]*$")thenselection=$answerfiif [ -z "$selection" ]thenechoecho "Invalid lunch combo: $answer"return 1fiexport TARGET_BUILD_APPS=# 将selection中的-分割前半部分给product# 并调用函数check_product去检查是否存在这个配置文件local product=$(echo -n $selection | sed -e "s/-.*$//")check_product $productif [ $? -ne 0 ]thenechoecho "** Don't have a product spec for: '$product'"echo "** Do you have the right repo manifest?"product=fi# 将selection中的-分割前半部分给variant# 并调用函数check_variant来检查这个值是否是:eng,user,debuguserlocal variant=$(echo -n $selection | sed -e "s/^[^\-]*-//")check_variant $variantif [ $? -ne 0 ]thenechoecho "** Invalid variant: '$variant'"echo "** Must be one of ${VARIANT_CHOICES[@]}"variant=fiif [ -z "$product" -o -z "$variant" ]thenechoreturn 1fi# 将变量product赋值给TARGET_PRODUCT# 将变量variant赋值给TARGET_BUILD_VARIANT# 将TARGET_BUILD_TYP的环境变量设置为releaseexport TARGET_PRODUCT=$productexport TARGET_BUILD_VARIANT=$variantexport TARGET_BUILD_TYPE=releaseecho# 设置更多的环境变量set_stuff_for_environmentprintconfig
}

lunch命令如果没有带参数,直接菜单选择,他的格式如下:

lunch<product_name>-<build_variant>

product_name必须是你定义好的产品配置,build_variant必须是eng,user,debuguser其中一个

lunch命令主要还是根据你输入的产品配置并且设置环境变量,环境变量和产品编译相关的主要是下面这些:

  • TARGET_PRODUCT 对应 product_name
  • TARGET_BUILD_VARIAN 对应 build_variant
  • TARGET_BUILD_TYPE 一般是release

最后他调用set_stuff_for_environment还会设置一些

3.Build相关的环境变量

我们注意看,执行完我们可以看到打印了很多的配置信息

这些配置将影响到我们的编译过程,我们来分析下

  • PLATFORM_VERSION_CODENAME

    • 表示平台版本的名称
  • PLATFORM_VERSION
    • Android平台的版本号
  • TARGET_PRODUCT
    • 所编译的产品名称
  • TARGET_BUILD_VARIANT
    • 所编译产品的类型
  • TARGET_BUILD_TYPE
    • 编译的类型,debug和release
  • TARGET_BUILD_APPS
    • 编译Android系统时,这个值为null,编译单模块时,这个值为所编译模块的路径
  • TARGET_ARCH
    • 表示编译目标的CPU架构
  • TARGET_ARCH_VARIANT
    • 表示编译目标的CPU架构版本
  • TARGET_CPU_VARIANT
    • 表示编译目标的CPU代号
  • TARGET_2ND_ARCH
    • 表示编译目标的第二CPU架构
  • TARGET_2ND_ARCH_VARIANT
    • 表示编译目标的第二CPU架构版本
  • TARGET_2ND_CPU_VARIANT
    • 表示编译目标的第二CPU代号
  • HOST_ARCH
    • 表示编译平台的架构
  • HOST_OS
    • 表示编译平台的操作系统
  • HOST_OS_EXTRA
    • 编译系统之外的额外信息
  • BUILD_ID
    • BUILD_ID会出现在版本信息中,可以利用
  • OUT_DIR
    • 编译结果输出的路径

这些变量中第二CPU是Android5.0才加入的,因为当运行64位环境的时候还要考虑32

对于环境变量的修改,可以放到产品的定义中,也可以临时的修改,比如:

make BUILD_ID="liuguilin"

4.Build系统的层次关系

我们lunch后,就是make了,make 后面可以接参数,也是编译过程的开始,make最终生成的也是zip以及各种img,Build会收集编译模块编译,然后复制二进制文件,产品配置文件等最后打包。

一套Android的源码能编译出多个不同的产品配置,我们反过来看,实际上我们也可以猜想到,源码的各个模块都是分开的,当我们选定了一个产品配置之后,Build会把他们拼接起来,我们来看下具体的工作流程:

在执行make后,实际上执行的是根目录/Makefile文件

include build/core/main.mk

可以看到,他里面就一行代码,执行了main.mk,我们查看main.mk就可以发现,他实际上是通过include将所有的mk都包含进来,最终在内存中形成一个编译脚本的集合,这才是最终形态的Makefile

Makefile是很庞大的,但是他主要由三种内容构成:变量定义,函数定义和目标,我们如果有必要,还是要看一下他们的亲戚关系:

这些mk文件的主要作用,我们来看下:

  • main.mk

    • Build的主控文件,主要作用是包含其他mk,以及定义几个最重要的编译目标,同时检查编译工具的版本,90如gcc等
  • help.mk
    • Build的帮助文件,输入make help会打印出相关的信息
  • config.mk
    • Build的配置文件,主要是区分各个产品的配置,并将这些编译器参数引入产品配置BoardConfig.mk,同时也配置了一些编译器的路径等
  • pathmap.mk
    • 给一些头文件所在的路径定义别名,将framework下的源码目录按类别引用
  • buildspec.mk
    • 产品定义的参数,不常用
  • envsetup.mk
    • 包含进product_config.mk文件并且根据其内容设置编译产品所需要的环境变量,并检查合法性,指定输出路径等
  • version_defaults.mk
    • 定义系统版本相关的配置
  • build_id.mk
    • 定义环境变量 BUILD_ID
  • product_config.mk
    • 包含系统所有的AndroidProdut.mk文件,并根据当前的产品配置来设置相关的环境变量
  • product.mk
    • 定义product_config.mk文件中使用的各种函数
  • combo/select.mk
    • 根据环境变量的设置,指定对应的系统和架构总所使用的工具和路径
  • clang/config.mk
    • 定义了LLVM编译器clang在不同架构下的路径和参数
  • dumpvar.mk
    • 打印输出本次编译的配置结果
  • cleanbuild.mk
    • 包含了源码中所有的CleanSoec.mk,定义编译目标dataclean和installclean
  • definitions.mk
    • 定义了大量Build中使用的函数,如果熟悉这些函数,编写产品配置会清晰很多
  • dex_preopt.mk
    • 定义了dex优化相关的路径和参数
  • pdk_config.mk
    • 编译pdk的配置文件
  • post_clean.mk
    • 比较当前系统的overlay目录和上一次build发生的变化
  • legacy_prebuilts.mk
    • 定义系统orebuild模块列表
  • Makefile
    • 系统最终编译完成所需要的各种目标和规则

总结:Build系统中定义了大量的编译变量,每一个都是很值得我们去了解熟悉的,虽然Google并没有给出太多的介绍。

5.分析main.mk文件

由于太多了,我们分段来分析

  • 1.检查gun make 的版本号是否大于等于3.81,否则报错停止编译
# Check for broken versions of make.
# (Allow any version under Cygwin since we don't actually build the platform there.)
ifeq (,$(findstring CYGWIN,$(shell uname -sm)))
ifneq (1,$(strip $(shell expr $(MAKE_VERSION) \>= 3.81)))
$(warning ********************************************************************************)
$(warning *  You are using version $(MAKE_VERSION) of make.)
$(warning *  Android can only be built by versions 3.81 and higher.)
$(warning *  see https://source.android.com/source/download.html)
$(warning ********************************************************************************)
$(error stopping)
endif
endif
  • 2.定义缺省的编译目标为“droid”,因此,命令make 相当于 “make droid”
# This is the default target.  It must be the first declared target.
.PHONY: droid
DEFAULT_GOAL := droid
$(DEFAULT_GOAL):
  • 3.引入几个mk文件,注意 include和-include的区别,后者包含的文件如果不存在不会报错,前者会停止编译
# Targets that provide quick help on the build system.
include $(BUILD_SYSTEM)/help.mk# Set up various standard variables based on configuration
# and host information.
include $(BUILD_SYSTEM)/config.mk# This allows us to force a clean build - included after the config.mk
# environment setup is done, but before we generate any dependencies.  This
# file does the rm -rf inline so the deps which are all done below will
# be generated correctly
include $(BUILD_SYSTEM)/cleanbuild.mk# Include the google-specific config
-include vendor/google/build/config.mkVERSION_CHECK_SEQUENCE_NUMBER := 5
-include $(OUT_DIR)/versions_checked.mk
  • 4.检查JAVA的版本是否是1.7或者1.6,不然则会报错推出,如果使用的版本是1.7,还要求必须是openJDK1.7版本
# Check for the correct version of java, should be 1.7 by
# default, and 1.6 if LEGACY_USE_JAVA6 is set.
ifeq ($(LEGACY_USE_JAVA6),)
required_version := "1.7.x"
required_javac_version := "1.7"
java_version := $(shell echo '$(java_version_str)' | grep '^java .*[ "]1\.7[\. "$$]')
javac_version := $(shell echo '$(javac_version_str)' | grep '[ "]1\.7[\. "$$]')
else # if LEGACY_USE_JAVA6
required_version := "1.6.x"
required_javac_version := "1.6"
java_version := $(shell echo '$(java_version_str)' | grep '^java .*[ "]1\.6[\. "$$]')
javac_version := $(shell echo '$(javac_version_str)' | grep '[ "]1\.6[\. "$$]')
endif # if LEGACY_USE_JAVA6ifeq ($(strip $(java_version)),)
$(info ************************************************************)
$(info You are attempting to build with the incorrect version)
$(info of java.)
$(info $(space))
$(info Your version is: $(java_version_str).)
$(info The required version is: $(required_version))
$(info $(space))
$(info Please follow the machine setup instructions at)
$(info $(space)$(space)$(space)$(space)https://source.android.com/source/initializing.html)
$(info ************************************************************)
$(error stop)
endif# Check for the current JDK.
#
# For Java 1.7, we require OpenJDK on linux and Oracle JDK on Mac OS.
# For Java 1.6, we require Oracle for all host OSes.
requires_openjdk := false
ifeq ($(LEGACY_USE_JAVA6),)
ifeq ($(HOST_OS), linux)
requires_openjdk := true
endif
endif# Check for the current jdk
ifeq ($(requires_openjdk), true)
# The user asked for java7 openjdk, so check that the host
# java version is really openjdk
ifeq ($(shell echo '$(java_version_str)' | grep -i openjdk),)
$(info ************************************************************)
$(info You asked for an OpenJDK 7 build but your version is)
$(info $(java_version_str).)
$(info ************************************************************)
$(error stop)
endif # java version is not OpenJdk
else # if requires_openjdk
ifneq ($(shell echo '$(java_version_str)' | grep -i openjdk),)
$(info ************************************************************)
$(info You are attempting to build with an unsupported JDK.)
$(info $(space))
$(info You use OpenJDK but only Sun/Oracle JDK is supported.)
$(info Please follow the machine setup instructions at)
$(info $(space)$(space)$(space)$(space)https://source.android.com/source/download.html)
$(info ************************************************************)
$(error stop)
endif # java version is not Sun Oracle JDK
endif # if requires_openjdk# Check for the correct version of javac
ifeq ($(strip $(javac_version)),)
$(info ************************************************************)
$(info You are attempting to build with the incorrect version)
$(info of javac.)
$(info $(space))
$(info Your version is: $(javac_version_str).)
$(info The required version is: $(required_javac_version))
$(info $(space))
$(info Please follow the machine setup instructions at)
$(info $(space)$(space)$(space)$(space)https://source.android.com/source/download.html)
$(info ************************************************************)
$(error stop)
endif
  • 5.将变量VERSIONS_CHECKED 和 BUILD_EMULATOR写入out/versions_checked.mk,下次build时会重新包含这些文件
$(shell echo 'VERSIONS_CHECKED := $(VERSION_CHECK_SEQUENCE_NUMBER)' \> $(OUT_DIR)/versions_checked.mk)
$(shell echo 'BUILD_EMULATOR ?= $(BUILD_EMULATOR)' \>> $(OUT_DIR)/versions_checked.mk)
  • 6.再包含3个mk
# Bring in standard build system definitions.
include $(BUILD_SYSTEM)/definitions.mk# Bring in dex_preopt.mk
include $(BUILD_SYSTEM)/dex_preopt.mkifneq ($(filter user userdebug eng,$(MAKECMDGOALS)),)
$(info ***************************************************************)
$(info ***************************************************************)
$(info Do not pass '$(filter user userdebug eng,$(MAKECMDGOALS))' on \
       the make command line.)
$(info Set TARGET_BUILD_VARIANT in buildspec.mk, or use lunch or)
$(info choosecombo.)
$(info ***************************************************************)
$(info ***************************************************************)
$(error stopping)
endififneq ($(filter-out $(INTERNAL_VALID_VARIANTS),$(TARGET_BUILD_VARIANT)),)
$(info ***************************************************************)
$(info ***************************************************************)
$(info Invalid variant: $(TARGET_BUILD_VARIANT)
$(info Valid values are: $(INTERNAL_VALID_VARIANTS)
$(info ***************************************************************)
$(info ***************************************************************)
$(error stopping)
endif# -----------------------------------------------------------------
# Variable to check java support level inside PDK build.
# Not necessary if the components is not in PDK.
# not defined : not supported
# "sdk" : sdk API only
# "platform" : platform API supproted
TARGET_BUILD_JAVA_SUPPORT_LEVEL := platform# -----------------------------------------------------------------
# The pdk (Platform Development Kit) build
include build/core/pdk_config.mk
  • 7.如果变量ONE_SHOT_MAKEFLTE的值不为空,那么将他定义的文件包含进来,当编译一个单独的模块时,ONE_SHOT_MAKEFLTE的值会设为一个模块的make文件路径,如果值ONE_SHOT_MAKEFLTE为空,说明正在编译整个系统,因此,调用findleayes.py脚本搜索系统里所有的Android.mk文件并将它们包含进来
ifneq ($(ONE_SHOT_MAKEFILE),)
# We've probably been invoked by the "mm" shell function
# with a subdirectory's makefile.
include $(ONE_SHOT_MAKEFILE)
# Change CUSTOM_MODULES to include only modules that were
# defined by this makefile; this will install all of those
# modules as a side-effect.  Do this after including ONE_SHOT_MAKEFILE
# so that the modules will be installed in the same place they
# would have been with a normal make.
CUSTOM_MODULES := $(sort $(call get-tagged-modules,$(ALL_MODULE_TAGS)))
FULL_BUILD :=
# Stub out the notice targets, which probably aren't defined
# when using ONE_SHOT_MAKEFILE.
NOTICE-HOST-%: ;
NOTICE-TARGET-%: ;# A helper goal printing out install paths
.PHONY: GET-INSTALL-PATH
GET-INSTALL-PATH:@$(foreach m, $(ALL_MODULES), $(if $(ALL_MODULES.$(m).INSTALLED), \echo 'INSTALL-PATH: $(m) $(ALL_MODULES.$(m).INSTALLED)';))else # ONE_SHOT_MAKEFILEifneq ($(dont_bother),true)
#
# Include all of the makefiles in the system
## Can't use first-makefiles-under here because
# --mindepth=2 makes the prunes not work.
subdir_makefiles := \$(shell build/tools/findleaves.py --prune=$(OUT_DIR) --prune=.repo --prune=.git $(subdirs) Android.mk)$(foreach mk, $(subdir_makefiles), $(info including $(mk) ...)$(eval include $(mk)))endif # dont_botherendif # ONE_SHOT_MAKEFILE
  • 8.根据编译类型来设置ro.secure的属性
## user/userdebug ##user_variant := $(filter user userdebug,$(TARGET_BUILD_VARIANT))
enable_target_debugging := true
tags_to_install :=
ifneq (,$(user_variant))# Target is secure in user builds.ADDITIONAL_DEFAULT_PROPERTIES += ro.secure=1ifeq ($(user_variant),userdebug)# Pick up some extra useful toolstags_to_install += debug# Enable Dalvik lock contention logging for userdebug builds.ADDITIONAL_BUILD_PROPERTIES += dalvik.vm.lockprof.threshold=500else# Disable debugging in plain user builds.enable_target_debugging :=endif# Turn on Dalvik preoptimization for libdvm.so user builds, but only if not# explicitly disabled and the build is running on Linux (since host# Dalvik isn't built for non-Linux hosts).ifeq (,$(WITH_DEXPREOPT))ifeq ($(DALVIK_VM_LIB),libdvm.so)ifeq ($(user_variant),user)ifeq ($(HOST_OS),linux)WITH_DEXPREOPT := trueendifendifendifendif# Disallow mock locations by default for user buildsADDITIONAL_DEFAULT_PROPERTIES += ro.allow.mock.location=0else # !user_variant# Turn on checkjni for non-user builds.ADDITIONAL_BUILD_PROPERTIES += ro.kernel.android.checkjni=1# Set device insecure for non-user builds.ADDITIONAL_DEFAULT_PROPERTIES += ro.secure=0# Allow mock locations by default for non user buildsADDITIONAL_DEFAULT_PROPERTIES += ro.allow.mock.location=1
endif # !user_variantifeq (true,$(strip $(enable_target_debugging)))# Target is more debuggable and adbd is on by defaultADDITIONAL_DEFAULT_PROPERTIES += ro.debuggable=1# Include the debugging/testing OTA keys in this build.INCLUDE_TEST_OTA_KEYS := true
else # !enable_target_debugging# Target is less debuggable and adbd is off by defaultADDITIONAL_DEFAULT_PROPERTIES += ro.debuggable=0
endif # !enable_target_debugging## eng ##ifeq ($(TARGET_BUILD_VARIANT),eng)
tags_to_install := debug eng
ifneq ($(filter ro.setupwizard.mode=ENABLED, $(call collapse-pairs, $(ADDITIONAL_BUILD_PROPERTIES))),)# Don't require the setup wizard on eng buildsADDITIONAL_BUILD_PROPERTIES := $(filter-out ro.setupwizard.mode=%,\$(call collapse-pairs, $(ADDITIONAL_BUILD_PROPERTIES))) \ro.setupwizard.mode=OPTIONAL
endif
ifndef is_sdk_build# Don't even verify the image on eng builds to speed startupADDITIONAL_BUILD_PROPERTIES += dalvik.vm.image-dex2oat-filter=verify-none# Don't compile apps on eng builds to speed startupADDITIONAL_BUILD_PROPERTIES += dalvik.vm.dex2oat-filter=interpret-only
endif
endif
  • 9.包含进post_clean.mk和legacypre_buildts.mk脚本,根据legacypre_buildts.mk中定义的变量GRANDFATHERED_ALL_PREBUILT检查是否有不在这个列表的prebuilt模块,如果有则报错推出
# Now with all Android.mks loaded we can do post cleaning steps.
include $(BUILD_SYSTEM)/post_clean.mkifeq ($(stash_product_vars),true)$(call assert-product-vars, __STASHED)
endifinclude $(BUILD_SYSTEM)/legacy_prebuilts.mk
ifneq ($(filter-out $(GRANDFATHERED_ALL_PREBUILT),$(strip $(notdir $(ALL_PREBUILT)))),)$(warning *** Some files have been added to ALL_PREBUILT.)$(warning *)$(warning * ALL_PREBUILT is a deprecated mechanism that)$(warning * should not be used for new files.)$(warning * As an alternative, use PRODUCT_COPY_FILES in)$(warning * the appropriate product definition.)$(warning * build/target/product/core.mk is the product)$(warning * definition used in all products.)$(warning *)$(foreach bad_prebuilt,$(filter-out $(GRANDFATHERED_ALL_PREBUILT),$(strip $(notdir $(ALL_PREBUILT)))),$(warning * unexpected $(bad_prebuilt) in ALL_PREBUILT))$(warning *)$(error ALL_PREBUILT contains unexpected files)
endif
  • 10.xxx

未完待续

Android系统篇(二)——Android编译核心Build系统相关推荐

  1. 第2章:Android的编译环境--build系统

    2.0 build简介 Android的build系统基于GNU Make 和shell 构建的一套编译环境.这套系统定义了大量的变量和函数,无论编写一个产品的配置文件还是一个模块的Android.m ...

  2. 树莓派 + Home Assistant + HomeKit 从零开始打造个人智能家居系统 篇二:初步配置 Home Assistant 并连接小米设备与 HomeKit

    树莓派 + Home Assistant + HomeKit 从零开始打造个人智能家居系统 篇二:初步配置 Home Assistant 并连接小米设备与 HomeKit 通过本篇教程,你将完成对 H ...

  3. 【Android取证篇】Android设备USB调试打开方式(开发者模式)

    [Android取证篇]Android设备USB调试打开方式(开发者模式) Android各个版本系统手机开启"USB调试"的入口不全相同,仅供参考-[蘇小沐] 1.[Androi ...

  4. Android面试题(二)Android高级/资深面试题

    Android面试题(一)Java基础 Android面试题(二)Android基础 Android面试题(三)Java虚拟机 Android面试题(四)设计模式 Android面试题(五)数据结构/ ...

  5. Android核心服务解析篇(二)——Android源码结构分析

    版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 获得Android源码后,我们来分析源码结构.源码的全部工程分为如下三个部分. ①Core Project:核心工程部分,这是建 ...

  6. Android日志[基础篇]二 Android Studio修改LogCat日志的颜色

    上一篇提到Android日志的5个级别的日志输出,在logcat里面设置自己喜欢或习惯的颜色,本文不只讲Android Sudio修改logcat的日志颜色. 代码和效果 代码 private voi ...

  7. Android入门篇二:使用意图在Activity之间传递数据

    首先,在这里稍微介绍一下意图(Intent)的概念: Intent(意图)主要是解决Android应用的各项组件之间的通讯. Intent 负责对应用中一次操作的动作.动作涉及数据.附加数据进行描述, ...

  8. Android自定义控件(二) Android下聚光灯实现

    前言 本篇文章记录Android下实现聚光灯功能,结合上篇文章[Android自定义控件(一) 可滑动的进度条]中进度条控件修改聚光灯的大小和背景透明度. 学习巩固自定义控件知识 说明 1.实现效果 ...

  9. Android系统篇之—-Android中的run-as命令引出升降权限的安全问题(Linux中的setuid和setgid)

    一.前言 最近一周比较忙,没时间写东西了,今天继续开始我们今天的话题:run-as命令,在上周的开发中,遇到一个问题,就是在使用run-as命令的时候出现了一个错误,不过当时因为工作进度的问题,这问题 ...

最新文章

  1. 度学习实践:如何使用Tensorflow实现快速风格迁移?
  2. 如何为人工智能建立正确的数据策略?
  3. Windows Phone播放视频流
  4. 安装Scrapy遇到Comand c:\users\lenovo\appdata\local\programs\python\python35\python.exe
  5. 青少年是维护网络安全的主力军
  6. SAP保存操作记录CDHDR和CDPOS表,通过修改屏幕字段,查找SAP字段表和字段
  7. python打印二进制内容,Python字节不打印二进制
  8. kylinH5框架之项目开发调试
  9. POJ2279-Mr. Young's Picture Permutations【线性dp】
  10. r语言worldclim数据_R语言空间数据分析(五):栅格数据处理
  11. 进入方法内快捷键_肝货|驱动安装流程驱动amp;快捷键设置(一)
  12. Android_Kotlin原生开发_声明变量与内置数据类型---Kotlin工作笔记002
  13. [tf] Unknown: Failed to get convolution algorithm. This is probably because cuDNN failed to initial
  14. 1431. 拥有最多糖果的孩子
  15. 时间序列-ARIMA模型调参检验实战
  16. 矩阵运算_Eigen使用_旋转矩阵/角轴/欧拉角/四元数相互转换
  17. 2022-2028年中国有色金属市场供需前景预测及投资策略研究报告
  18. vue 动态渲染表格序号列
  19. three.js 入门详解(一)
  20. PDF怎么转换成Word?来看这两个方法

热门文章

  1. dnf红眼补丁在哪下载_dnf红眼变红补丁下载
  2. C# Unsafe code may only appear if compiling with /unsafe
  3. 计算:光速运行一年的长度是多少米?(测试整数运算溢出)
  4. 香港计算机专业硕士学制几年,想读香港一年计算机硕士,懂行老哥来指导一下我这个迷茫的five...
  5. python中str,int,list,list(str),list(int)的相互转换
  6. Linux账号与身份管理
  7. java使用爬虫工具jsoup实现抓取网页的内容及图片并写入到word文档中
  8. 东大22春大学语文X《大学语文》在线平时作业2_100分资料非答案
  9. 洛谷P2905 [USACO08OPEN]农场危机Crisis on the Farm
  10. java1.8 xp_最新版Java8怎么在XP系统电脑上安装?