声明
- 在Android系统中经常会遇到一些系统原理性的问题,在此专栏中集中来讨论下。
- Android系统,为了能够更好的理解Android的Java世界的运行规律,此篇分析Android Java框架的结构。
- 此篇参考一些博客和书籍,代码基于Android 7.1.1,不方便逐一列出,仅供学习、知识分享。
1 Java框架层结构
Android系统Java 框架层库的实体内容主要有 3个,如下所示:
- Java 框架库:framework.jar
- Java 服务库:services.jar
- 资源包:framework-res.apk
在目标系统中,Java框架层的几个库都位于framework目录中。Java 框架层的主体结构如图所示:
Java 框架库是系统的核心,其中定义并实现了 Android 中大多数的Java 类,也提供作为标准接口的框架层API。
Java 服务库包含了一些比较复杂的服务,为框架层提供一部分功能的实现。服务库也具有 Java 框架层中一个主要的程序入口。进入此入口运行后,服务库将形成Java 框架层的一个在后台长期运行的程序。
资源包是一个 apk 文件,其中没有 Java 代码,基本是由纯资源组成的包。资源包是 Java框架层唯一的包含资源和工程描述文件的包,框架层所有的资源和组件定义均包含在资源包中。
与 Android 本地层次中各部分分离的实现不同,Java 框架层实现的合性比较强,3个库之间具有相互依赖的关系。随着 Android 系统的演进,以上3 个库主体的结构没有变化。
2 Android Java 层的API
2.1 Java 框架层API的含义
Java 层API的含义是一个基于Android 系统下 Java 应用层的标准接口。按照Android系统的标准,原则上第4 层的应用程序通过 Java 层的 API 调用第3 层的 Java 架。Android 设备提供 API,第三方应用程序基于 API 的开发标准化的 API作为二者之间的协议,可以让系统具有兼容性。
提示:在Android 的 SDK 环境中开发 Java 应用,一般只能调用框架层 API。而在源代码环境中开发 Java 应用,可以调用框架层非 API部分的其他接口。
框架层API的来源主要有以下的方面。
- Java 核心库 core.jar 中对外的部分(主要为java.,javax. 和 org.*的各个包)。
- Java 框架库 framework.jar 中对外的部分(为 android.*的各个包)。
框架层API 还包括与资源相关的内容 (android.R 包),是根据资源文件自动生成,并没有 Java 源代码与之对应。用预测 core-unit.jar 包当中也有部分框架层API (junit.*包)。
Java 框架层具有很多类,每个类中具有自己域(字段,属性)和方法,所谓框架层 API,只是这些类中标准化的部分。不标准的部分不属于框架层 API,但依然可以被位于 Android系统APP层的应用程序所调用,这样有可能带来兼容性问题。
Android 版本升级中的API兼容性如图所示:
标准化的 API保证了兼容性,主要体现在两个方面:
- 第一方面,基于前一个版本 API 开发的第三方应用程序包,标准化的 API 可以在后面版本的 Android 设备上运行。由于下一版本的 API 包含了上一个版本的 API,因此提供标准化 API 的Android 设备的功能会逐渐增加,而不会减少。因此,基于上一个版本 API 开发出的第三方应用程序包所调用的功能,在下面的版本中依然具有,它是可以运行的。
- 第二方面,基于某个级别源代码开发具体的 Android 设备,标准化的 API 应当可以运行对于此 API 级别的所有应用程序包。具体的 Android 设备在开发过程中可以更改 API,原则是只能增加而不能减少。这样其对应标准 API 级别的设备功能就依然还具有,基于某个API(及其之前)开发的第三方应用程序包,在其上面预计依然是可以运行的。
在源代码的 prebuilt/sdk/<API 级别>/目录中,有一个名称为 android.jar 的包。在编译的时候,也可以根据 Java 代码的情况生成这个包。android.jar 是一个表示 Java 标准API的“桩”,用于在 SDK 环境的开发。android.jar 并不是一个提供实际功能的库,它的存在只是为了在 SDK 环境中开发应用程序包的时候,可以找到标准 API 定义的各个内容。
2.2 API 的描述文件
API 的描述文件是对Java层的标准API的描述。它们是位于frameworks/base/api/目录中的各个文件。
其中,current.xml 文件表示当前的API,可以根据当前的代码改动情况自动生成,在Android某个版本的源代码包中,current.xml 应该和当前的 API 级别的 xml 文件是一样的,在改动代码后重新生成的current.xml 文件将可能不一样。
在Android 全系统编译的时候,如果源代码和 current.xml 描述的API不一致,编译过程将报错,可以使用如下的命令更新current.xml文件:
make update-api
执行后,将根据当前的代码情况更新 current.xml 文件本身。
API 描述文件使用 XML 语法的各种标签来描述 Java 语言中的各个元素,主要使用的标签如下所示:
<api></api>: 包含所有内容的标签,位于文件的根部。
<package></package>: Java 包,将包含其中的各个内容。
<class></class>: Java 类。
<interface></interface>: Java 接口。
<implements></implements>: 当前类或接口所实现的接口。
<constructor><constructor>: 类的构造函数
<method></method>: 方法
<parameter></parameter>: 方法中的参数
<field> </field>: 域(字段,属性)。
<exception></exception>: 异常。
以上的标签在描述 API 的 xml 文件中具有层次包含关系,各个标签具有不同的 xml 属性描述其中不同的内容。
2.3 @hide 和 @Deprecated
对于 Android Java 框架层的代码,android.*子包所有公共类、属性和方法等,将被视为框架层 API。对于不希望作为 API 使用的内容,可以在源代码的注释中使用@hide 描述,将其隐藏。
@hide 描述可以隐藏方法、域,也可以是整个类。
在Android 的框架层 API 中,有一些 API 属于不赞成使用的(也称之为过时的)。它们般是在比较旧的 API级别上公开的接口,但是到了新的API 级别上,已经被其他接口所代替。由于要保证向后兼容性,因此这种接口是不能被去掉的,只能被标示为不赞成使用( deprecated)。处理不赞成使用的内容的方法是在代码中加入@Deprecated。
在Android 系统中,“不赞成使用”的 API依然是 API的一部分,在用的时候和正常的 API类似(编译的过程中可能报出 warning)。所谓“不赞成使用”的意思只是 Android 官方不再推荐使用此类接口,而建议使用更健全的其他接口替代。在兼容性和内容更新两个方面具有矛盾的时候,不赞成使用的 API 的定义实际上是种折中的解决方式。
3 Java 框架库 framework.jar
Java 框架库(framework.jar)是 Java 框架层的主体,提供了Android 的 Java 框架层中大多数 API 类和内部类的实现。
3.1 框架库的组成和作用
Java 框架库提供了 Java 框架层大部分的 Java 类的实现。Java 框架库的代码为frameworks/base/中的若于个子目录中,生成 Java 的包:framework.jar,放置到目标系统的/system/framework目录中。
Java 框架库的主要分布在 frameworks/base/的以下几个子目录中:
dockdroid@zj-x86:base$ tree -L 1
.
├── Android.mk
├── api
├── CleanSpec.mk
├── cmds
├── compiled-classes-phone
├── core //Android 核心包
├── data
├── docs
├── drm
├── graphics //图形处理包
├── include
├── keystore
├── libs
├── location //定位相关内容
├── media //多媒体和音频相关内容
├── MODULE_LICENSE_APACHE2
├── native
├── nfc-extras
├── NOTICE
├── obex
├── opengl //Android OpenGL 3D 实现
├── packages
├── preloaded-classes
├── proto
├── rs
├── samples
├── sax
├── services
├── telecomm
├── telephony //电话部分相关内容
├── test-runner
├── tests
├── tools
└── wifi //无线局域网相关内容
在以上的目录中都包含了一个 Java 子目录,也就是 Java 框架层的代码。其中,core是主要的目录,实现了 Android 系统所定义的大部分 Java 类。其他的部分通常是和硬件有些关系的,每个部分单独使用一个目录。
框架库 framework,jar 内容众多,但它的确只是一个“库”,而不是一个运行时的概念只有在其中的各个 Java 类被调用的时候,该库中才有可能得到运行。
3.2 框架库的 API
框架中的类分为对外的 API 和内部类,其中的内容放在不同的目录中
<path>/java/android/: android.* 包中的内容,其中包括 API
<path>/java/com/: com.* 包中的内容,其中都是内部类。
<path>表示框架库的一个模块,例如:core、graphics 或 media 等。也就是说,在模块的 java 路径中,只有 android 目录才有可能提供对外的 API,com 目录当中都是内部使用的包。当然,android 目录中的内容也不都是 API,在代码中使用@hide 可以隐藏内容。除此之外,还可以隐藏各个目录中的package.html。
各个目录中的 package.html 文件为对这个部分的描述。在这个文件中可以使用标记,将整个目录的内容“隐藏”。
例如:core/java/android/hardware 中的 package.html文件,如下所示:
<HTML>
<BODY>
<p>Provides support for hardware features, such as the camera and other sensors. Be aware that
not all Android-powered devices support all hardware features, so you should declare hardware
that your application requires using the <a
href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code
<uses-feature>}</a> manifest element.</p>
</BODY>
</HTML>
以上的 package.html 文件只包含了一些描述性的内容,在编译 API 和生成文档的同时将生成相应的信息。
core/java/android/中的ddm、pim、server 等目录中的内容,虽然是Android 的子包,但是这几个子包的内容整体隐藏,不作为 API。整体隐藏的方法就是在它们的 package.html 文件中增加隐藏信息。例如,pim目录中的 package.html 文件如下所示:
<html>
<body>
{@hide}
</body>
</html>
3.3 框架库的编译结构
由于框架库的内容比较多,其编译的包含关系也是比较复杂的。frameworks/base/目录中的Android.mk 文件负责 framework.jar 包的编译。其主要的片段如下所示:
ifneq ($(ANDROID_BUILD_EMBEDDED),true)
include $(CLEAR_VARS)
# FRAMEWORKS_BASE_SUBDIRS comes from build/core/pathmap.mk
LOCAL_SRC_FILES := $(call find-other-java-files,$(FRAMEWORKS_BASE_SUBDIRS))
# EventLogTags files.
LOCAL_SRC_FILES += \
core/java/android/app/admin/SecurityLogTags.logtags \
core/java/android/content/EventLogTags.logtags \
core/java/android/speech/tts/EventLogTags.logtags \
core/java/android/webkit/EventLogTags.logtags \
core/java/com/android/internal/logging/EventLogTags.logtags \
LOCAL_SRC_FILES += \
core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl \
core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl \
......
LOCAL_MODULE := framework
LOCAL_DX_FLAGS := --core-library --multi-dex
LOCAL_JACK_FLAGS := --multi-dex native
LOCAL_RMTYPEDEFS := true
ifeq ($(EMMA_INSTRUMENT_FRAMEWORK),true)
LOCAL_EMMA_INSTRUMENT := true
endif
include $(BUILD_JAVA_LIBRARY)
这里使用宏FRAMEWORKS BASE_SUBDIRS所指定的各个Java 源代码的路径这个宏由 build/core/目录的 pathmap.mk 文件定义。
3.4 属性机制
Android 的属性机制在 Java 框架层也有对应的接口,可以进行属性的r/w。
与属性相关的内容在以下目录中:frameworks/base/core/java/android/os/。
与属性相关的是android.os 包中的 SystemProperties 类,其基本内容如下所示:
public class SystemProperties
{
public static final int PROP_NAME_MAX = 31;
public static final int PROP_VALUE_MAX = 91;
private static final ArrayList<Runnable> sChangeCallbacks = new ArrayList<Runnable>();
private static native String native_get(String key);
private static native String native_get(String key, String def);
private static native int native_get_int(String key, int def);
private static native long native_get_long(String key, long def);
private static native boolean native_get_boolean(String key, boolean def);
private static native void native_set(String key, String def);
private static native void native_add_change_callback();
/**
* Get the value for the given key.
* @return an empty string if the key isn't found
* @throws IllegalArgumentException if the key exceeds 32 characters
*/
public static String get(String key) {
if (key.length() > PROP_NAME_MAX) {
throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
}
return native_get(key);
}
/**
* Get the value for the given key.
* @return if the key isn't found, return def if it isn't null, or an empty string otherwise
* @throws IllegalArgumentException if the key exceeds 32 characters
*/
public static String get(String key, String def) {
if (key.length() > PROP_NAME_MAX) {
throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
}
return native_get(key, def);
}
......
}
由于使用了@hide标记,SystemProperties 是一个内部的类,其中只包含一些静态的方法,因此 Java 中的属性操作其实就是一个不需要上下文的方法集合。Java 中的属性机制实际上依赖于本地的 libcutils 库中的属性r/w操作来完成 SystemProperties 是对它的一个简单的封装。
3.5 套接字机制
Android 套接字具有一定的特殊性,在 Java 层也具有相应的套接字处理方法。Android 套接字相关的内容在以下目录中:frameworks/base/core/java/android/net/。
套接字的内容涉及 android.net 包中的几个类,其中 LocalSocketAddress、LocalSocket 和 LocalServerSocket 几个类是 API 的一部分,而 LocalSocketImpl 则是内部实现类 LocalSocketAddress 表示套接字的地址,构造函数如下所示:
/**
* Creates an instance with a given name.
*
* @param name non-null name
* @param namespace namespace the name should be created in.
*/
public LocalSocketAddress(String name, Namespace namespace) {
this.name = name;
this.namespace = namespace;
}
/**
* Creates an instance with a given name in the {@link Namespace#ABSTRACT}
* namespace
*
* @param name non-null name
*/
public LocalSocketAddress(String name) {
this(name,Namespace.ABSTRACT);
}
LocalSocketAddressNamespace 是一个表示套接字的类型的枚举值,其定义内容如下所示:
public enum Namespace {
/** A socket in the Linux abstract namespace */
ABSTRACT(0),
/**
* A socket in the Android reserved namespace in /dev/socket.
* Only the init process may create a socket here.
*/
RESERVED(1),
/**
* A socket named with a normal filesystem path.
*/
FILESYSTEM(2);
/** The id matches with a #define in include/cutils/sockets.h */
private int id;
Namespace (int id) {
this.id = id;
}
/**
* @return int constant shared with native code
*/
/*package*/ int getId() {
return id;
}
}
以上几个数值和底层的相对应。其中,Android 系统使用的通信特别手段是保留套接字RESERVED,也是由init.rc 在 /dev/socket 目录中建立的。
LocalSocket 类是套接字操作所使用的主要类。通常建立 LocalSocket 的实例后,需要连接到某个地址,表示与那个地址的套接字进行通信。LocalSocket 中包括了控制方法和数据方法。
LocalSocket 的控制方法如下所示:
/**
* Connects this socket to an endpoint. May only be called on an instance
* that has not yet been connected.
*
* @param endpoint endpoint address
* @throws IOException if socket is in invalid state or the address does
* not exist.
*/
public void connect(LocalSocketAddress endpoint) throws IOException {
synchronized (this) {
if (isConnected) {
throw new IOException("already connected");
}
implCreateIfNeeded();
impl.connect(endpoint, 0);
isConnected = true;
isBound = true;
}
}
/**
* Binds this socket to an endpoint name. May only be called on an instance
* that has not yet been bound.
*
* @param bindpoint endpoint address
* @throws IOException
*/
public void bind(LocalSocketAddress bindpoint) throws IOException {
implCreateIfNeeded();
synchronized (this) {
if (isBound) {
throw new IOException("already bound");
}
localAddress = bindpoint;
impl.bind(localAddress);
isBound = true;
}
}
/**
* Closes the socket.
*
* @throws IOException
*/
@Override
public void close() throws IOException {
implCreateIfNeeded();
impl.close();
}
建立一个 LocalSocket 之后,就可以调用 connect() 连接到使用 LocalSocketAddress 表示的某个地址,bind() 方法则只有当地址没有被绑定的时候才需要使用。LocalSocket 的数据方法如下所示:
/**
* Retrieves the input stream for this instance.
*
* @return input stream
* @throws IOException if socket has been closed or cannot be created.
*/
public InputStream getInputStream() throws IOException {
implCreateIfNeeded();
return impl.getInputStream();
}
/**
* Retrieves the output stream for this instance.
*
* @return output stream
* @throws IOException if socket has been closed or cannot be created.
*/
public OutputStream getOutputStream() throws IOException {
implCreateIfNeeded();
return impl.getOutputStream();
}
获得输入、输出流之后,相当于得到了套接字的数据访问句柄,可以进一步通过 InputStream 和 OutputStream 抽象类中的方法对套接字进行R/W 。LocalServerSocket 用于建立一个服务性质的 Socket,其内容如下所示:
public LocalServerSocket(String name)
public LocalServerSocket(FileDescriptor fd)
public LocalSocket accept()
public void close()
public FileDescriptor getFileDescriptor()
public LocalSocketAddress getLocalSocketAddress()
LocalServerSocket 实际上只用于使用抽象套接字,Android 系统保留的套接字不使用 LocalServerSocket。建立后通过 accept() 可以获得一个 LocalSocket 的实例,根据它可以进行后续的操作。
LocalSocket 和 LocalServerSocket 都是基于关键性的内部类为 LocalSocketImpl 实现的,LocalSocketImpl 类的结构如下所示:
class LocalSocketImpl {
/**
* An input stream for local sockets. Needed because we may
* need to read ancillary data.
*/
class SocketInputStream extends InputStream {...}
/**
* An output stream for local sockets. Needed because we may
* need to read ancillary data.
*/
class SocketOutputStream extends OutputStream {}
public void create(int sockType)
public void close()
protected void connect(LocalSocketAddress address, int timeout)
public void bind(LocalSocketAddress endpoint)
protected void listen(int backlog)
protected void accept(LocalSocketImpl s)
}
LocalSocketImpl 中的几个方法为 protected 类型,只能被本包中的 LocalSocket 和 LocalServerSocket 所调用。LocalSocket 主要使用其中 bind()、connect() 等几个方法。
LocalServerSocket 使用其中的 bind()、listen()和 accept() 方法。LocalSocketImp 的实现最终需要依赖于本地部分。对于抽象套接字(基于网络协议)部分,直接调用了 Linux 底层的套接字建立接口;Android 保留套接字的部分,则是基于libcutils 中的内容来实现的。
4 Java服务库 services.jar
Java 服务库(services.jar)提供了 Java 框架层中公共的后台运行部分。
4.1 服务库的组成和作用
Android 中 Java 框架层的服务部分的目录为:frameworks/base/services/core/java/,其中的Android.mk 文件负责这个包的编译,其中内容生成Java 包:services.jar,将被放置到目标
系统的路径:/system/framework。
服务库当中只包含实现了com.android.server 一个Java 包,这是一个内部类,不提供对外的API。 com.android.server 中具有众多的 Java 类。SystemServer 是其中的入口部分,服务库中还有执行某个部分具体功能的服务。
服务库的核心内容为系统服务器(SystemServer),它提供了 Android 框架层的主要入口。进入这个入口之后,将形成一个长时间运行的后台循环。这也是 Android 系统的 Java 层运行时主要的公共部分。
服务库中的各个子模块提供了不同方面的功能,这部分内容的名字通常为 Service。它们被 SystemServer主入口启动,随后进行自己的运行。主要的一些 Service 如下所示:
- 活动管理服务(am/ActivityManagerService)
- 包管理服务(pm/PackageManagerService)
- 窗口管理器服务(wm/WindowManagerService)
- 电源管理服务(power/PowerManagerService)
- 输入法(Ipnut/MethodManagerService)
- 通知服务(notification/NotificationManagerService)
- 墙纸管理器服务(wallpaper/WallpaperManagerService)
- 警报器服务(AlarmManagerService)
- 光系统服务(lights/LightsService)
- 振动器服务(VibratorService)
- 电池服务(BatteryService)
- 定位服务(location/LocationManagerService)
Java 服务库 (services.jar) 和 Java 框架库 (framework.jar) 在功能上是互相依存的。服务库本身需要使用框架库中定义的各个基础类,而框架库中的部分功能又是依赖于服务库中的“服务”来实现的。
4.2 服务管理器 SystemServer
代码位置:frameworks/base/services/java/com/android/server/SystemServer.java,SystemServer的启动过程可参考:cm-14.1 Android系统启动过程分析(6)-SystemServer进程启动过程
4.3 主要服务的功能
Java 服务库中的服务为框架层提供了功能的实现。一个通常的使用方式是,在框架库中定义接口,在服务库中实现这个接口,框架库通过接口调用服务库。这些服务是 Java 框架层的“公用部分”,它们通常有类似的运行行为:
- 它们自已在后台运行一个循环
- 又提供接口让外部可以对其进行调用
服务库中很多类实现了 aidl 定义的接口中所描述的功能,然后由 Java 框架库根据这些 aidl 接口对其进行调用。服务库中的很多类继承了某个 aidl 文件中定义的 XXX.Stub 类,如下所示:
public class VibratorService extends IVibratorService.Stub {...}
public class LocationManagerService extends ILocationManager.Stub {...}
有些类也直接继承了 Binder,如下所示:
public class DiskStatsService extends Binder {...}
上面两种继承方式,都是通过 Java 层的 Binder 进程间通信机制,向其他 Java 程序提供接口。随着 Android 系统的发展,服务库中的内容有所增加。这里各个组件实现的基本模式是通过实现 aidl 向框架库提供接口的实现,但是少数所谓“服务”也不是用这种方式实现的。
4.3.1 活动管理服务(am/ActivityManagerService)
4.3.2 窗口管理器服务(wm/WindowManagerService)
4.3.3 包管理服务(pm/PackageManagerService)
4.3.4 电源管理服务(power/PowerManagerService)
4.3.5 输入法(Ipnut/MethodManagerService)
4.3.6 通知服务(notification/NotificationManagerService)
4.3.7 墙纸管理器服务(wallpaper/WallpaperManagerService)
4.3.8 外设相关的几个服务
4.4 启动结束时的处理
Android 系统 Java 部分的启动过程本身是由服务库来负责的。服务库中的一个部分提供了启动完成时间点执行的操作。
frameworks/base/core/java/com/android/server/BootReceiver.java 文件在Java 框架层定义了一个 BroadcastReceiver 的组件。它处理了名称为 android.intent.action.BOOT_COMPLETED 的动作,其中的 onReceive() 方法将在 Android 系统启动之后执行。
BootReceiver 中默认进行启动信息的处理,例如,在系统第一次启动完成后,保存一些信息到数据库中。如果需要系统启动完成后,处理一些全局性的工作,可以通过在 BootReceiver.java 文件增加调用内容来完成。
5 资源包 framework-res.apk
资源包 (framework-res.apk) 包含了 Java 框架层的所有资源,也包括在 API 中声明的资源和内部资源。
5.1 资源包的组成和作用
Android 资源包的目录为:frameworks/base/core/res/,其中的 Android.mk 文件负责这个包的编译。生成Android 的应用程序包:framework-res.apk,将被放置到目标系统的路径:/system/framework 。
资源包 framework-res.apk 是 Android 的Java 框架层的唯一 apk 文件,其他均为 Jar 包。因此框架层中的资源文件、资产文件和 AndroidManifest.xml 文件都包含在这个资源包中,并且这个资源包中不包含 Java 代码。除此之外,资源包其他部分的结构和应用程序层的一个应用程序工程基本相同。
资源包主要包括 res 资源目录、assets 资产目录和 AndroidManifest.xml 文件,没有源代码目录。
其中 res 中的内容为资源文件,各个子目录的含义如下所示:
anim | 动画文件 |
color | 颜色定义 |
drawable-<修饰符> | 图片等可绘制内容,修饰符通常是不同屏幕的支持 |
layout-<修饰符> | 布局文件,修饰符为不同的方向 |
values-<修饰符> | 数值定义文件,修饰符通常是不同语言的支持 |
xml-<修饰符> | XML格式的文件 |
raw-<修饰符> | 原始文件,修饰符通常是不同语言的支持 |
其中的各个资源文件将会自动生成相应描述资源 id 的 Java 源代码文件,也就是out/target/common/R/android 目录中R.java文件,片段如下所示:
package android;
public final class R {
public static final class anim {
public static final int accelerate_decelerate_interpolator=0x010a0004;
/** Acceleration curve matching Flash's quadratic ease out function.
*/
public static final int accelerate_interpolator=0x010a0005;
public static final int anticipate_interpolator=0x010a0007;
public static final int anticipate_overshoot_interpolator=0x010a0009;
public static final int bounce_interpolator=0x010a000a;
public static final int cycle_interpolator=0x010a000c;
......
}
R类中的 R.anim、R.array 等类,其中的内容是表示资源的一些整数值。这个 R.java 文件将作为源代码被编入Java 框架库 framework.jar 中。
res/values-<修饰符>/目录中的各个文件为不同数值定义,各个文件的功能如下所示:
ids.xml | 定义android.R.id 类中的各个数值,为一些固定的 id |
strings.xml | 定义android.R.string 类中的各个数值,为各个字符串 |
arrays.xml | 定义android.R.array 类中的各个数值,为各个数组 |
attrs.xml | 定义android.R.attrs 类中的各个数值,为各个属性 |
styles.xml 和 themes.xml | 定义android.R.style 类中的各个数值,为样式和主题 |
colors.xml | 定义android.R.color 类中的各个数值,也作为可绘制内容使用 |
dimens.xml | 定义android.R.dimen 类中的各个数值,为尺寸值 |
各文件定义均包含在和标签中。注意:这些文件的名称只是命名上的习惯,并非强制使用的名称。实际起到作用的是文件中各个标签定义内容的使用,在所有 xml文件中的意义都是一样的。
5.2 作为API的资源id
资源包的部分资源是公共资源。它们的 id 也是 Android 标准 API的一部分通常使用android.R.*类中的整数值来表示。
资源包的 res/values/ 目录中的 public.xml 文件用于定义公共资源的 id。截取其中一段如下所示:
<public type="drawable" name="sym_action_chat" id="0x0108008e" />
<public type="drawable" name="sym_action_email" id="0x0108008f" />
<public type="drawable" name="sym_call_incoming" id="0x01080090" />
以上的内容由类型drawable 表示了android.R.drawable 类,其中的名称为 sym_action_email 和 sym_call_incoming 的值,它们的本质是整数值。
在 public.xml中定义的各个资源,为系统公共的资源,具有固定的 id。它们等同于 Java 层的API,在系统编译的时候也会根据 public.xml 更新 current.xml 文件。
5.3 资源包 AndroidManifest.xml 文件
资源包的 AndroidManifest.xml 文件定义了框架层的包名(package=“android”)和运行用户(android:sharedUserId=“android.uid.system”),并声明了许可和内部组件。
资源包没有 Java 源代码目录 (src),却有 AndroidManifest.xml 文件,其中除了全局的声明,还有系统预定义的许可以及框架层的应用程序组件 (Activity、Service 等) 的声明。例如,前面提到的服务库中的 BootReceiver 广播接收器,在这个AndroidManifest.xml文件中就有如下的定义:
<receiver android:name="com.android.server.BootReceiver"
android:systemUserOnly="true">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
组件对应的代码通常在 Java 框架库和Java 服务库中。
Java 框架库 firamework.jar 和服务 services.jar 包括一些内部的活动、服务、广播接收器等。但是这两个包都是以 jar 文件形式构建的,不能包含 AndroidManifest.xml 和资源文件,因此相应的内容包含在资源包 framework-res.apk 当中。
5 策略库
策略库(android.policyjar)负责实现 Java框架层中一些细节的行为。
待补充