追根溯源话虚拟[ZT]



在目前的 x86 服务器上,虚拟化技术已经成为或者即将成为潮流。但从整个 IT 业界的发展来看,虚拟化技术的历史远远超过了 x86 虚拟化技术的 9 年。早在上世纪 60 年代,美国的计算机学术界就开始了虚拟技术的萌芽。1959年 6月在国际信息处理大会上,克里斯托弗的一篇《计算机分时应用》的论文,被认为是虚拟化技术的最早论述。

今天,虚拟化技术已经出现在了很多首席信息官(CIO)的预定任务中。在一次第三方调查当中,75% 的 CIO 都同意虚拟化技术是目前的一项投资重点,因为他们已经开始注重减少他们的服务器的数量以减少能源使用、降低成本。甚至于,虚拟化技术目前正在走向主流技术市场并且已经逐步成为数据中心环境的标准组成部分。

为什么需要虚拟化

实际上,虚拟化技术的初衷就是为了实现更高的设备利用率,使用户能够尽可能地利用系统资源。也就是说,如果你能够在单个服务器上虚拟多个系统,就能够以少数几台计算机完成所有工作,这显然能够节省耗电、空间、冷却和管理开支。考虑到确定服务器利用状况的困难,虚拟化技术需要支持动态迁移(Live Migration)。动态迁移允许操作系统能够迁移到另一台全新的服务器上,从而减少当前主机的负载。

有这样一句话,叫做“更多虚拟,更少管理(Virtualize more, manage less)”。IBM 将虚拟定义为不受物理限制的资源逻辑表达。更简单地说,IBM 将虚拟诠释为可以将一个物理设备作为很多虚拟资源(分区)来使用,或者令多个异构资源的行为看起来就如同是一个大的资产(集合)。

正是由于虚拟化技术能够降低 TCO(总拥有成本),提高资源的利用率和应用上的灵活性,虚拟化技术后来也在 UNIX 服务器、小型机上得到了应用。可以说,经过多年的发展,虚拟化技术在高端产品上的应用日臻成熟。不过,由于真正使用大型机和小型机的用户毕竟还是少数,加上各家产品和技术之间并不兼容,致使虚拟化曲高和寡。

服务器虚拟化溯源

尽管目前的虚拟化技术热潮是由于该技术在 x86 服务器上的迅速普及引发的,但虚拟化技术的最初来源却不在 x86 架构上,而是大型主机。最早使用虚拟化技术的是 IBM 7044 计算机,IBM 之后在上世纪 60 年代还开发了型号为 Model 67 的 System/360 主机。Model 67 主机通过虚拟机监视器(Virtual Machine Monitor)虚拟所有的硬件接口。在早期的计算中, 操作系统被称做 Supervisor,能够运行在其它操作系统之上的操作系统被称做 hypervisor。其中,VMM 直接运行在底层硬件上, 允许执行多个虚拟机(VM),每一个 VM 运行自己的操作系统实例(CMS,Conversational Monitor System)。随后,VM 继续发展。今天,你能够在 System z9 主机上发现 VM, 它甚至能够向后兼容到 System/360。

由于虚拟化技术技术在商业应用上的优势,RISC 服务器与小型机成为了虚拟化技术第二波受益者。1999年,IBM 公司在 AS/400 上提出了上“逻辑分区(LPAR)”技术和新的高可用性集群解决方案。在 POWER 管理程序上运行的 AS/400 LPAR 令单台服务器工作起来如同 12 个独立的服务器。而在 2002 年,IBM 还更进一步,其 AIX5L v5.2 还首次包括了 IBM 实现的动态逻辑分区(DLPAR)。DLPAR 允许在无需重启系统的情况下,将包括处理器、内存和其它组件在内的系统资源分配给独立的分区。这种在不中断运行的情况下进行资源分配的能力不仅令系统管理变得更加轻松,而且因为能够更好地使用资源而帮助降低总拥有成本。

不过,尽管惠普、Sun 公司也跟随 IBM 在自己的 RISC 服务器上提供了虚拟化技术,但由于真正使用大型机和小型机的用户还是少数,加上各家产品和技术之间并不兼容,虚拟化技术仍旧不太被公众所关注。目前,主要的 UNIX 厂商均支持 64 路 SMP 的虚拟。并且普遍能实现 1/X 量级 CPU 的微调,例如 IBM 宣称可以实现 1/100 CPU 量级的调整,惠普则可以实现 1/20 量级的调整。在应用上,UNIX 上的虚拟化也非常成熟,IBM 的客户订购的 System i5 595 中有 82% 具备逻辑分区功能,IBM 客户管理的分区总数超过 45000 个。在中国,甚至有用户在一台 System p 系列服务器上运行了 9 个逻辑分区。

而现在,虚拟化技术的发展已经惠及到了 x86 架构。此前,虚拟化技术在 x86 架构上进展缓慢的主要原因有二:x86 架构本身不适合进行虚拟化,这个障碍已经由英特尔、AMD 修改 x86 处理器的指令集得到解决;另一个原因则是 x86 处理器的性能不足,也由于 x86 处理器在性能上的飞速提高得到了解决。由于 x86 架构的广泛普及,x86 架构上的虚拟化技术也得到了比以前多得多的关注。

不过,与已经有多年历史的 UNIX 服务器、大型主机上的虚拟化技术相比,x86 服务器上的虚拟化仍旧处于早期阶段——根据英特尔的蓝图,在处理器当中集成硬件辅助虚拟化指令只是 IA 平台上的第一步,而在第二步则要实现 I/O 方面的虚拟化,直到最后实现整个 IA 平台的虚拟化。也就是说,目起的 x86 平台上,目前仅仅能够实现在处理器级别的虚拟化,在 I/O 以及其他方面的虚拟化还需要进一步的发展。不仅如此,x86 架构上的虚拟化技术还无法完美实现虚拟分区之间动态迁移,而这些在 UNIX 平台、大型主机上早已不是问题。IBM 公司最近发布的 POWER6 处理器甚至还提供了 Live Partition Mobility 功能,允许实现活动分区的在线迁移。目前,x86 架构上的虚拟化技术的最高规划是支持 8路 SMP 系统,可以实现对单个 CPU 资源的配置。

浅析存储虚拟化

相对于在服务器虚拟化技术在规范上的相对成熟,存储虚拟化技术在这方面的进展相对缓慢。按照定义,存储虚拟化可以分为三种层次:在主机层面进行存储虚拟化;在网络层次进行存储虚拟化;在设备层面进行存储虚拟化。三种技术都有相应的厂商的支持,也都有不少的用户。比较而言,IBM 在存储虚拟化方面所占据的市场份额更大,在技术实现上也更早。根据 IDC 的估计,虚拟存储市场在 2005 年年底的数据容量为28.1PB,而 IBM 管理着大约 15PB 的数据。

早就 1978年,IBM 就获得了 RAID(冗余独立磁盘阵列)概念的专利。作为一种存储虚拟形式,RAID 首先将物理设备组合为池,然后从这一池中“切割”出一组虚拟逻辑单元(LUN)并将其提供给主机。通过使用镜像和奇偶性,这些逻辑单元第一次拥有了比底层物理磁盘驱动器更高的可用性。虽然直到 1988年 IBM 与加利福尼亚州立大学伯克利分校的研究人员携手之后才开发出一个实用的版本,但这一专利技术却是第一次将虚拟化的概念引入到了存储之中。

在 2003年 5月,IBM 推出可提供数据块级存储虚拟的 SAN 卷控制器(SAN Volume Controller),在业界第一次允许客户拥有一个对其存储基础架构进行管理的控制界面。在 2004年 10月,IBM 推出了拥有逻辑分区(LPAR)功能的 DS8000。通过使用 IBM POWER5 微处理器和 IBM 虚拟引擎技术,DS8000 在实现高性能的同时,降低了多种业务应用的成本。利用IBM虚拟引擎技术,DS8000 系列中的某些型号既可作为单一的大型存储系统使用,也可作为拥有逻辑分区(LPAR)功能的多个存储系统。通过使用 LPAR,客户可以选择更高效地使用计算机资源以及降低对关键数据中心的空间、功耗和散热需求。另外,IBM 还宣布自己的虚拟软件可以管理所有的 EMC 磁盘阵列。

小结

实际上,不论是刚刚谈的服务器虚拟化,还是存储虚拟化,甚至网络虚拟化、数据虚拟化等等,都只是部件级的虚拟化。虚拟化技术的未来应当是将整个数据中心虚拟化,使用户能够获得一个随需应变数据中心。

IBM 早在 40 多年前就率先在大型主机上使用了虚拟技术,并在此后在自己的系统和软件中注入了各种虚拟技术,实现不同服务器、软件、存储和网络的自动管理和优化。IBM 虚拟技术和自动化技术的结合帮助减少了支持 IT 运行所需的人员数量。今天,IBM 可以将客户数据中心中超过 80% 的部分实现虚拟。为进一步发挥虚拟的威力,IBM 正在创建包括所有物理和虚拟系统的集成管理视图。IBM 早在 5 年前最先推出具有自管理功能的自动化技术,并为市场提供了一系列最成熟的自动化功能,包括在超过 75 种软件、硬件和服务产品中提供了 500 多种不同的虚拟功能,可以自动检测各种系统、事务处理、工作流或业务流程何时处于运行不正常的状态,并在不影响系统其它部分的情况下采取纠正措施。这些功能已经远远超出了系统管理软件的范畴并包括了芯片技术。具有"智能搜索"特性的软件和软件工具可以寻找和清除各种故障,自主管理像 Blue Gene 超级计算机和大型主机这样的服务器和存储设备。
<think> 我们正在追踪`Resources.getSystem().getAssets().getLocales()`的调用链。根据引用[4],我们知道在`LocalePicker.java`中有这样的调用。但我们需要更深入地了解这个调用在系统源码中的实现。 步骤: 1. `Resources.getSystem()`: 返回一个全局的Resources对象,用于访问系统资源。 2. `getAssets()`: 返回AssetManager实例。 3. `getLocales()`: 返回一个字符串数组,表示系统支持的语言区域。 我们需要从源码中找出`getLocales()`方法的实现。根据Android源码,`AssetManager`类中定义了`getLocales()`方法。 让我们逐步分析: 1. **Resources.getSystem()**: 在`Resources.java`中,`getSystem()`是一个静态方法,返回一个全局的Resources对象,它只加载系统资源(不包含应用资源)。 源码径:`frameworks/base/core/java/android/content/res/Resources.java` ```java public static Resources getSystem() { synchronized (sSync) { Resources ret = mSystem; if (ret == null) { ret = new Resources(); mSystem = ret; } return ret; } } ``` 在构造函数中,会获取系统AssetManager: ```java private Resources() { // 创建系统AssetManager mAssets = AssetManager.getSystem(); // ... 其他初始化 } ``` 2. **AssetManager.getSystem()**: 在`AssetManager.java`中,`getSystem()`返回一个单例的系统AssetManager实例。 源码径:`frameworks/base/core/java/android/content/res/AssetManager.java` ```java public static AssetManager getSystem() { synchronized (sSync) { if (sSystem == null) { sSystem = new AssetManager(true /*system*/); } return sSystem; } } ``` 注意:这里传入了一个参数`true`,表示这是系统AssetManager。 3. **AssetManager的构造**: 在构造系统AssetManager时,会调用`init(true)`(在较新版本中可能是`init()`,但会标记为系统): ```java private AssetManager(boolean isSystem) { if (isSystem) { synchronized (this) { init(true); } } } ``` 在`init`方法中,会设置系统资源径(如`/system/framework`和`/system/app`等),并重建所有资源。 4. **AssetManager.getLocales()**: 这个方法返回当前AssetManager实例中可用的区域设置(locales)列表。它实际上是一个本地方法,通过JNI调用底层C++代码。 ```java public final String[] getLocales() { return getLocales(true); } private native String[] getLocales(boolean excludeDirs); ``` 本地方法实现在`android_content_res_AssetManager.cpp`中。 5. **本地方法实现**: 在`android_content_res_AssetManager.cpp`中,找到对应的本地方法: ```cpp static jobjectArray android_content_res_AssetManager_getLocales(JNIEnv* env, jobject clazz, jboolean excludeDirs) { AssetManager* am = assetManagerForJavaObject(env, clazz); if (am == NULL) { return NULL; } // 获取区域列表 std::vector<std::string> locales; am->getLocales(&locales, excludeDirs); // 将C++的字符串向量转换为Java的字符串数组 jobjectArray array = env->NewObjectArray(locales.size(), env->FindClass("java/lang/String"), NULL); for (size_t i = 0; i < locales.size(); i++) { jstring str = env->NewStringUTF(locales[i].c_str()); env->SetObjectArrayElement(array, i, str); env->DeleteLocalRef(str); } return array; } ``` 这里的`am->getLocales(&locales, excludeDirs)`会调用`AssetManager`的成员函数`getLocales`。 6. **C++层的AssetManager::getLocales**: 在`AssetManager.cpp`中: ```cpp void AssetManager::getLocales(std::vector<std::string>* locales, bool includeDirs) const { ResTable* res = mResources; if (res != NULL) { res->getLocales(locales, includeDirs); } } ``` 这里调用了`ResTable`的`getLocales`方法。 7. **ResTable::getLocales**: 在`ResourceTypes.cpp`中: ```cpp void ResTable::getLocales(std::vector<std::string>* locales, bool includeDirs) const { if (mPackageGroups.size() == 0) { return; } // 这里会遍历所有资源包,收集区域信息。 // 具体实现会从资源包中读取区域列表。 ... } ``` 总结: 调用链为: Java: Resources.getSystem() -> AssetManager.getSystem() -> AssetManager.getLocales() JNI: android_content_res_AssetManager_getLocales() -> C++: AssetManager::getLocales() -> ResTable::getLocales() 这个调用最终会读取系统资源包(包括framework-res.apk和其他系统apk)中定义的区域列表。 注意:系统支持的语言区域列表实际上是由系统资源包中的资源决定的。在构建系统资源包时(如frameworks/base/core/res),会在res目录下放置不同语言区域的资源目录(如values-zh-rCN),这些目录会被打包进framework-res.apk。当系统启动时,AssetManager会扫描这些apk,提取可用的区域信息。 因此,如果我们想要修改系统支持的语言列表,除了修改`config_localeList`(用于在设置中显示)外,还需要在系统资源包中添加对应语言区域的资源目录(如添加values-xx-rXX目录),并重新编译系统镜像。 注意:在引用[4]中提到,修改语言列表可以通过修改`Resources.getSystem().getAssets().getLocales()`返回的结果,但实际上这个结果是由系统资源包中的资源决定的。所以,添加新的语言区域需要在系统资源包中添加对应的资源目录。 相关问题: §§相关问题§§ 1. 如何向系统资源包中添加新的语言资源? 2. 修改系统语言列表后,为什么在设置中可能看不到新添加的语言? 3. 系统资源包中的资源是如何被AssetManager加载的? 4. 在Android系统中,如何动态获取系统支持的语言列表? </think> ### `Resources.getSystem().getAssets().getLocales()` 源码溯源分析 #### 1. **调用链起点:`Resources.getSystem()`** 在 Android 源码中,`Resources.getSystem()` 返回系统级资源对象: ```java // frameworks/base/core/java/android/content/res/Resources.java public static Resources getSystem() { synchronized (sSync) { if (mSystem == null) { mSystem = new Resources(); // 创建系统资源实例 } return mSystem; } } ``` 此方法返回全局唯一的系统资源实例(不依赖 Context),用于访问系统内置资源[^2]。 --- #### 2. **AssetManager 获取:`getAssets()`** 系统资源对象内部持有 `AssetManager` 实例: ```java // frameworks/base/core/java/android/content/res/Resources.java private Resources() { mAssets = AssetManager.getSystem(); // 获取系统级 AssetManager // 初始化资源配置... } ``` `AssetManager.getSystem()` 返回系统全局 AssetManager 单例[^1]。 --- #### 3. **核心实现:`AssetManager.getLocales()`** 最终调用本地方法获取语言列表: ```java // frameworks/base/core/java/android/content/res/AssetManager.java public final String[] getLocales() { return getLocales(true); // 调用 Native 方法 } private native String[] getLocales(boolean excludeDirs); ``` --- #### 4. **JNI 层实现** 本地方法在 `android_content_res_AssetManager.cpp` 中实现: ```cpp // frameworks/base/core/jni/android_content_res_AssetManager.cpp static jobjectArray android_content_res_AssetManager_getLocales( JNIEnv* env, jobject clazz, jboolean excludeDirs) { AssetManager* am = assetManagerForJavaObject(env, clazz); std::vector<std::string> locales; am->getLocales(&locales, excludeDirs); // 调用 C++ 层 // 将 C++ 向量转换为 Java 数组 jobjectArray array = env->NewObjectArray(locales.size(), env->FindClass("java/lang/String"), NULL); for (size_t i = 0; i < locales.size(); i++) { jstring str = env->NewStringUTF(locales[i].c_str()); env->SetObjectArrayElement(array, i, str); } return array; } ``` --- #### 5. **C++ 层实现** 最终在 `AssetManager.cpp` 中处理语言列表: ```cpp // frameworks/base/libs/androidfw/AssetManager.cpp void AssetManager::getLocales(std::vector<std::string>* locales, bool includeDirs) const { for (const auto& package : mPackageGroups) { for (const auto& locale : package->getLocales()) { locales->emplace_back(locale); // 收集所有语言标签 } } // 去重排序... } ``` 实际数据来源: 1. 解析 `/system/etc/locale-config.xml` 系统配置文件 2. 扫描 `/system/framework` 下的资源包(如 `framework-res.apk`) 3. 读取资源包中的 `resources.arsc` 资源表 --- #### 6. **数据生成机制** 语言列表最终来源于 AAPT2 编译资源时生成的资源表: 1. 编译时扫描 `values-xx` 资源目录 2. 提取 BCP-47 语言标签(如 `zh-CN`) 3. 写入 APK 中的 `resources.arsc` 资源表 4. 系统启动时加载到内存 #### 调用链总结: $$ \text{Java: Resources.getSystem()} \rightarrow \text{AssetManager.getLocales()} $$ $$ \downarrow $$ $$ \text{JNI: android_content_res_AssetManager_getLocales()} $$ $$ \downarrow $$ $$ \text{C++: AssetManager::getLocales()} \rightarrow \text{ResourceTable} $$
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值