Android系统原理性问题分析 - Android Java框架层的结构

news2024/11/19 18:33:56

声明

  • 在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保证了兼容性,主要体现在两个方面:

  1. 第一方面,基于前一个版本 API 开发的第三方应用程序包,标准化的 API 可以在后面版本的 Android 设备上运行。由于下一版本的 API 包含了上一个版本的 API,因此提供标准化 API 的Android 设备的功能会逐渐增加,而不会减少。因此,基于上一个版本 API 开发出的第三方应用程序包所调用的功能,在下面的版本中依然具有,它是可以运行的。
  2. 第二方面,基于某个级别源代码开发具体的 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框架层中一些细节的行为。
待补充

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/541404.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

资产处置求变,京东拍卖如何做好“价值枢纽”?

近年来&#xff0c;随着资产处置市场规模快速成长以及互联网行业飞速发展&#xff0c;金融资产、司法拍卖、罚没物资等处置方式从最初单纯线下拍卖逐渐落地互联网&#xff0c;服务专业化程度也在不断提高。为更好适应市场变化&#xff0c;满足不断增长的市场需求&#xff0c;5月…

NISP二级证书含金量如何

国家信息安全水平考试&#xff08;National Information Security Test Program&#xff0c;简称NISP&#xff09;&#xff0c;是由中国信息安全测评中心实施培养国家网络空间安全人才的项目。 为培养更多优秀的实践型网络安全人才&#xff0c;中国信息安全测评中心推出了国家…

替代MySQL半同步复制,Meta技术团队推出MySQL Raft共识引擎

作者&#xff1a;Anirban Rahut、Abhinav Sharma、Yichen Shen、Ahsanul Haque 原文链接&#xff1a;https://engineering.fb.com/2023/05/16/data-infrastructure/mysql-raft-meta/ 译者&#xff1a;ChatGPT 责编&#xff1a;张红月 MySQL Raft是MySQL数据库中一种基于Raft协议…

探索LeetCode【0010】正则表达式匹配(已懂,未练习)

目录 0.1 题目0.2 补充示例1. 参考B站视频2. 官方答案的评论-可用3. chatGPT的思路和解法-可用 0.1 题目 题目链接&#xff1a;【0010】正则表达式匹配 给你一个字符串 s 和一个字符规律 p&#xff0c;请你来实现一个支持 . 和 * 的正则表达式匹配。 . 匹配任意单个字符* 匹…

2023 RSAC|和衷共济 共同应对网络安全挑战

作为全球最具规模的安全大会&#xff0c;2023年RSA Conference的落幕也为安全行业的“何去何从”带来一定的启发性。 今年大会的主题是“Strong together”&#xff0c;主要来自于海伦凯勒的名言: “ Alone we can do so little; together we can do so much. ” 纵观2022年…

做完这个测试项目,我终于决定辞职·····

很迷茫&#xff0c;然后过得非常不如意&#xff0c;倒不是上一年的职业目标没达到&#xff0c;而是接下来的路根本不知道如何走。在没解决这个问题之前&#xff0c;或者说没搞清楚自己的方向之前&#xff0c;是迟迟不能落笔的&#xff0c;啊不&#xff0c;应该是落键盘。 下班…

JavaWeb-RequestResponse的使用

Request&Response 今日目标 掌握Request对象的概念与使用掌握Response对象的概念与使用能够完成用户登录注册案例的实现能够完成SqlSessionFactory工具类的抽取 1&#xff0c;Request和Response的概述 Request是请求对象&#xff0c;Response是响应对象。这两个对象在我们…

德尔玛IPO首日破发,市值蒸发超4亿

今日&#xff08;5月18日&#xff09;&#xff0c;小米“代工厂”广东德尔玛科技股份有限公司&#xff08;下称“德尔玛”&#xff0c;301332.SZ&#xff09;正式在深交所挂牌上市。 德尔玛此次IPO募资净额为12.31亿元&#xff0c;开盘价为14.81元/股&#xff0c;与发行价持平…

Call to undefined function bcadd()

先介绍一下当前使用的环境。同学们可以比较一下&#xff0c;看本篇文章是否可以提供帮助。 docker 部署 nginx 1.24php 8.1-fpm 再介绍一下框架&#xff0c;使用的是 "laravel 9.33.0" 其实这里跟 laravel 框架和 nginx 是没太多关系的&#xff0c;因为我们主要是使…

MySQL高级_第09章_性能分析工具的使用

MySQL高级_第09章_性能分析工具的使用 在数据库调优中&#xff0c;我们的目标就是 响应时间更快&#xff0c;吞吐量更大。利用宏观的监控工具和微观的日志分析可以帮我们快速找到调优的思路和方式。 1. 数据库服务器的优化步骤 当我们遇到数据库调优问题的时候&#xff0c;该…

Windows平台软件开发模型总结:V型模型、瀑布模型、迭代模型、增量模型、螺旋模型、原型模型

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天总结一下Windows平台软件开发模型总结&#xff1a;V型模型、瀑布模型、迭代模型、增量模型、螺旋模型、原型模型。 很多人可能知道了&#xff0c;那就是在我们浙江省&#xff0c;从2021年年初到现在&…

内网 monorepo 配置指南(PNPM、YARN)

此处的内网是指没办法连接互联网进行依赖下载的环境&#xff0c;本文以windows平台为例 背景说明 绝大部分政府机关、国有企业都是在内网开发&#xff0c;无法从互联网同步依赖&#xff0c;就需要另辟蹊径解决项目依赖的问题。 传统的单包项目还好&#xff0c;从互联网机器将…

兼顾降本与增效,我们对存算分离的设计与思考

“降本增效”是最近企业常被提及的关键字&#xff0c;作为新时代企业发展的数据大脑&#xff0c;企业大数据团队需要持续探索如何在有限资源下创造更多价值。本文将以场景为"引"&#xff0c;技术为"核"&#xff0c;介绍如何基于 StarRocks 全新的存算分离架…

软考软件设计师真题与答案解析

1、2020下半年基础知识&#xff08;上午题&#xff09; 1、某计算机系统的CPU主频为2.8GHz。某应用程序包括3类指令&#xff0c;各类指令的CPI(执行每条指令所需要的时钟周期数)及指令比例如’下表所示。执行该应用程序时的平均CPI为&#xff08; &#xff09;&#xff1b;运算…

2023 操作系统 R 复习大纲( 适用于软件 21 级)

目录 01.操作系统的定义 02.操作系统的基本类型及特征 1.批处理操作系统&#xff08;单、多道&#xff09; 2.分时操作系统 3.实时操作系统 03.操作系统的功能及特征 04.进程的定义、特征 05.进程基本状态及其转换原因 06.进程互斥、同步 07.进程控制块的内容、作用 …

Android Studio开发之路 (一)开发环境搭建以及问题记录

一、安装 Android Studio 安装配置教程 这个文章讲的很全面&#xff08;包括了jdk的配置&#xff09;&#xff0c;我安装了1.8.0版本的JDK 以及 2022.2.1版本的Android Studio ,安装目录都是自定义的&#xff0c;安装完成之后的目录如下&#xff08;项目目录也放到这里了&…

医院上线“报告中心”,实现报告查询“四个更好”

为进一步提升患者的就诊体验&#xff0c;不少医院部署云影像后&#xff0c;再次上线博为软件报告中心信息系统&#xff0c;患者和家属动动手指就能在自己手机上随时随地看到检查检验报告&#xff0c;彻底告别传统的纸质报告单方式&#xff0c;实现检查检验数据永久保存。 博为…

【Java多线程编程】wait与notify方法详解

前言 我们知道&#xff0c;线程的调度是无序的&#xff0c;但有些情况要求线程的执行是有序的。因此&#xff0c;我们可以使用 wait() 方法来使线程执行有序。 本期讲解 Java 多线程中 synchronized 锁配套使用的 wait 方法、notify方法和notifyAll方法&#xff0c;以及 wait 方…

jQuery 操作 DOM 及 CSS

jQuery 操作 DOM 及 CSS 1. jQuery 修改|获取页面元素文本及属性值 text() - 设置或返回所选元素的文本内容 html() - 设置或返回所选元素的内容&#xff08;包括 HTML 标签&#xff09; val() - 设置或返回表单字段的值 attr() - 方法用于获取属性值。 1.1 举例&#xff…

win11亮度条消失解决方法之一

一、前言 1、本人电脑情况&#xff1a;联想小新Pro16&#xff0c;win11家庭版 2、联想技术工程师三种方式联系方式&#xff08;需提供电脑背后的编号&#xff09;&#xff1a; 1&#xff09; 通过预装的联想电脑管家&#xff0c;获取在线人工专家支持&#xff08;管家链接 h…