小工具知识网

当前位置: 首页 > 行业知识 > Android12系统环境变量设置

行业知识

Android12系统环境变量设置

2026-11-06 11:19:09 来源:互联网转载

欢迎大家关注我的微信公众号:Xndroid,探索Android技术,解锁移动世界。

最近在移植百度Apollo Cyber通信框架至安卓系统中,发现Cyber本身依赖于环境变量来实现服务的初始化配置。相应地,我也需要在安卓系统中引入这些环境变量,并确保在Native服务启动时这些环境变量已经准备就绪。

由于此前我对环境变量的了解并不多,于是研究学习了一下Android系统中关于环境变量的相关配置,这篇博文即对此做了一个记录。

背景简介

首先我们需要探究一下为什么我们需要环境变量。环境变量是一组动态的,可手动编辑、设置的值。一般而言,我们程序的运行往往会依赖于各种各样的配置,这些配置我们可以以配置文件的形式存放于本地文件系统中,再让程序在运行时进行解析从而获取配置,这是一种比较通用的做法;而另一种比较通用的做法是将这些配置写入环境变量,程序在运行时自动读取环境变量即可。前者适合配置比较多的情况,而后者则适合配置少且配置可能需要多进程共享的情况,比较灵活。

可以说环境变量是非常重要的,没有环境变量的支持,无论是Windows系统中的程序还是Linux系统中的程序都无法正常运行。

环境变量分为两类:全局环境变量和局部环境变量。全局环境变量是全局可见的,所有进程可见;而局部变量则针对部分进程可见。 

查看环境变量

 如何查看系统的环境变量呢,这里提供两个命令:env或者printenv命令,如下所示:

_=/system/bin/envANDROID_DATA=/dataHOME=/ANDROID_TZDATA_ROOT=/apex/com.android.tzdataANDROID_STORAGE=/storageANDROID_ASSETS=/system/appTERM=xterm-256colorANDROID_SOCKET_adbd=19ANDROID_ART_ROOT=/apex/com.android.artCYBER_DOMAIN_ID=71CYBER_PATH=/data/cyberEXTERNAL_STORAGE=/sdcardDOWNLOAD_CACHE=/data/cacheLOGNAME=rootSYSTEMSERVERCLASSPATH=/system/framework/com.android.location.provider.jar:/system/framework/services.jar:/system/framework/ethernet-service.jar:/system/framework/car-frameworks-service.jar:/apex/com.android.appsearch/javalib/service-appsearch.jar:/apex/com.android.media/javalib/service-media-s.jar:/apex/com.android.permission/javalib/service-permission.jarDEX2OATBOOTCLASSPATH=/apex/com.android.art/javalib/core-oj.jar:/apex/com.android.art/javalib/core-libart.jar:/apex/com.android.art/javalib/okhttp.jar:/apex/com.android.art/javalib/bouncycastle.jar:/apex/com.android.art/javalib/apache-xml.jar:/system/framework/framework.jar:/system/framework/framework-graphics.jar:/system/framework/ext.jar:/system/framework/telephony-common.jar:/system/framework/voip-common.jar:/system/framework/ims-common.jar:/apex/com.android.i18n/javalib/core-icu4j.jar:/system/framework/android.car.jarBOOTCLASSPATH=/apex/com.android.art/javalib/core-oj.jar:/apex/com.android.art/javalib/core-libart.jar:/apex/com.android.art/javalib/okhttp.jar:/apex/com.android.art/javalib/bouncycastle.jar:/apex/com.android.art/javalib/apache-xml.jar:/system/framework/framework.jar:/system/framework/framework-graphics.jar:/system/framework/ext.jar:/system/framework/telephony-common.jar:/system/framework/voip-common.jar:/system/framework/ims-common.jar:/apex/com.android.i18n/javalib/core-icu4j.jar:/system/framework/android.car.jar:/apex/com.android.appsearch/javalib/framework-appsearch.jar:/apex/com.android.conscrypt/javalib/conscrypt.jar:/apex/com.android.ipsec/javalib/android.net.ipsec.ike.jar:/apex/com.android.media/javalib/updatable-media.jar:/apex/com.android.mediaprovider/javalib/framework-mediaprovider.jar:/apex/com.android.os.statsd/javalib/framework-statsd.jar:/apex/com.android.permission/javalib/framework-permission.jar:/apex/com.android.permission/javalib/framework-permission-s.jar:/apex/com.android.scheduling/javalib/framework-scheduling.jar:/apex/com.android.sdkext/javalib/framework-sdkextensions.jar:/apex/com.android.tethering/javalib/framework-connectivity.jar:/apex/com.android.tethering/javalib/framework-tethering.jar:/apex/com.android.wifi/javalib/framework-wifi.jarSHELL=/bin/shANDROID_BOOTLOGO=1ASEC_MOUNTPOINT=/mnt/asecHOSTNAME=trout_x86USER=rootTMPDIR=/data/local/tmpPATH=/product/bin:/apex/com.android.runtime/bin:/apex/com.android.art/bin:/system_ext/bin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbinANDROID_ROOT=/systemANDROID_I18N_ROOT=/apex/com.android.i18ntrout_x86:/ # 

 除了这个命令以外,我们还可以使用echo来获取某个具体环境变量的值,如下所示:

TMPDIR=/data/local/tmpPATH=/product/bin:/apex/com.android.runtime/bin:/apex/com.android.art/bin:/system_ext/bin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbinANDROID_ROOT=/systemANDROID_I18N_ROOT=/apex/com.android.i18ntrout_x86:/ # echo $USERroottrout_x86:/ # echo $ANDROID_SOCKET_adbd19

 需要说明的是,上述方法仅针对全局环境变量有效,如果是查看局部环境变量,我们可以使用set命令,如下所示:

trout_x86:/ $ setDOWNLOAD_CACHE=/data/cacheEPOCHREALTIME=1682412013.723827EXTERNAL_STORAGE=/sdcardHOME=/HOSTNAME=trout_x86IFS=$' \t\n'KSHEGID=2000KSHGID=2000KSHUID=2000KSH_VERSION='@(#)MIRBSD KSH R59 2020/05/16 Android'LINESLOGNAME=shellOPTIND=1PATH=/product/bin:/apex/com.android.runtime/bin:/apex/com.android.art/bin:/system_ext/bin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbinPATHSEP=:PGRP=24010PIPESTATUS[0]=1PPID=574PS1=$'${|\n\tlocal e=$?\n\n\t(( e )) && REPLY+="$e|"\n\n\treturn $e\n}$HOSTNAME:${PWD:-?} $ 'PS2='> 'PS3='#? 'PS4='[$EPOCHREALTIME] 'PWD=/RANDOM=30514SECONDS=3878SHELL=/bin/shSYSTEMSERVERCLASSPATH=/system/framework/com.android.location.provider.jar:/system/framework/services.jar:/system/framework/ethernet-service.jar:/system/framework/car-frameworks-service.jar:/apex/com.android.appsearch/javalib/service-appsearch.jar:/apex/com.android.media/javalib/service-media-s.jar:/apex/com.android.permission/javalib/service-permission.jarTERM=xterm-256colorTMOUT=0TMPDIR=/data/local/tmpUSER=shellUSER_ID=
 环境变量加载

 那么Android系统是如何加载环境变量的呢,我们可以先看看/system/core/rootdir/Android.mk文件中的内容(节选):

$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/init.environ.rc.in@echo "Generate: $ $@"@mkdir -p $(dir $@)$(hide) cp $ 

 Android.mk中这部分其实就引入了一个关键的文件:init.environ.rc.in,在Android12.1中其内容定义如下:

# set up the global environmenton early-init    export ANDROID_BOOTLOGO 1    export ANDROID_ROOT /system    export ANDROID_ASSETS /system/app    export ANDROID_DATA /data    export ANDROID_STORAGE /storage    export ANDROID_ART_ROOT /apex/com.android.art    export ANDROID_I18N_ROOT /apex/com.android.i18n    export ANDROID_TZDATA_ROOT /apex/com.android.tzdata    export EXTERNAL_STORAGE /sdcard    export ASEC_MOUNTPOINT /mnt/asec    %EXPORT_GLOBAL_ASAN_OPTIONS%    %EXPORT_GLOBAL_GCOV_OPTIONS%    %EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS%    %EXPORT_GLOBAL_HWASAN_OPTIONS%

 该文件内定义的内容其实就是全局的环境变量设置,通过在rc启动文件中使用export命令进行导入。但这只是初始定义的文件,是无法直接生效的。

在上面Android.mk展示的片段中,会将 init.environ.rc.in 中的中%EXPORT_GLOBAL_ASAN_OPTIONS%、%EXPORT_GLOBAL_GCOV_OPTIONS%、%EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS%、%EXPORT_GLOBAL_HWASAN_OPTIONS%使用sed命令进行替换,替换的值来源于Android.mk中获取到的EXPORT_GLOBAL_ASAN_OPTIONS、EXPORT_GLOBAL_GCOV_OPTIONS、EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS、EXPORT_GLOBAL_HWASAN_OPTIONS变量,这部分变量的赋值逻辑如下:

# init.environ.rcinclude $(CLEAR_VARS)LOCAL_MODULE_CLASS := ETCLOCAL_MODULE := init.environ.rcLOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0LOCAL_LICENSE_CONDITIONS := noticeLOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)EXPORT_GLOBAL_ASAN_OPTIONS :=ifneq ($(filter address,$(SANITIZE_TARGET)),)  EXPORT_GLOBAL_ASAN_OPTIONS := export ASAN_OPTIONS include=/system/asan.options  LOCAL_REQUIRED_MODULES := asan.options $(ASAN_OPTIONS_FILES) $(ASAN_EXTRACT_FILES)endifEXPORT_GLOBAL_HWASAN_OPTIONS :=ifneq ($(filter hwaddress,$(SANITIZE_TARGET)),)  ifneq ($(HWADDRESS_SANITIZER_GLOBAL_OPTIONS),)    EXPORT_GLOBAL_HWASAN_OPTIONS := export HWASAN_OPTIONS $(HWADDRESS_SANITIZER_GLOBAL_OPTIONS)  endifendifEXPORT_GLOBAL_GCOV_OPTIONS :=ifeq ($(NATIVE_COVERAGE),true)  EXPORT_GLOBAL_GCOV_OPTIONS := export GCOV_PREFIX /data/misc/traceendifEXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS :=ifeq ($(CLANG_COVERAGE),true)  EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS := export LLVM_PROFILE_FILE /data/misc/trace/clang-%20m.profrawendif

 由此,在编译阶段对 init.environ.rc.in 进行处理,得到init.environ.rc,打包后位于根目录;init进程在启动时就会读取该rc启动文件,进行环境变量的设置。

在我的环境中, init.environ.rc 文件内容如下:

# set up the global environmenton early-init    export ANDROID_BOOTLOGO 1    export ANDROID_ROOT /system    export ANDROID_ASSETS /system/app    export ANDROID_DATA /data    export ANDROID_STORAGE /storage    export ANDROID_ART_ROOT /apex/com.android.art    export ANDROID_I18N_ROOT /apex/com.android.i18n    export ANDROID_TZDATA_ROOT /apex/com.android.tzdata    export EXTERNAL_STORAGE /sdcard    export ASEC_MOUNTPOINT /mnt/asec

除了init.environ.rc.in中定义的全局环境变量,还有部分环境变量是在init.rc中进行导入的,如DOWNLOAD_CACHE环境变量。如下所示:

    # enable armv8_deprecated instruction hooks    write /proc/sys/abi/swp 1    # Linux's execveat() syscall may construct paths containing /dev/fd    # expecting it to point to /proc/self/fd    symlink /proc/self/fd /dev/fd    export DOWNLOAD_CACHE /data/cache                              # This allows the ledtrig-transient properties to be created here so    # that they can be chown'd to system:system later on boot     write /sys/class/leds/vibrator/trigger "transient"

 那么环境变量具体是如何加载的呢,加载的过程其实就在init进程中进行。在rc文件中定义的export导入环境变量会被init进程以command的形式执行,从而导入到系统环境中,具体代码细节可以参考—— system/core/init/action_manager.cpp与system/core/init/action.cpp:

void ActionManager::ExecuteOneCommand() {    {           auto lock = std::lock_guard{event_queue_lock_};        // Loop through the event queue until we have an action to execute        while (current_executing_actions_.empty() && !event_queue_.empty()) {            for (const auto& action : actions_) {                if (std::visit([&action](const auto& event) { return action->CheckEvent(event); },                               event_queue_.front())) {                    current_executing_actions_.emplace(action.get());                }               }               event_queue_.pop();        }       }       if (current_executing_actions_.empty()) {        return;    }       auto action = current_executing_actions_.front();    if (current_command_ == 0) {        std::string trigger_name = action->BuildTriggersString();        LOG(INFO) 

上一篇:织梦CMS隐藏路径a揭秘攻略!

下一篇:开源工业软件:SCADA系统开源