實現 Java SDK 庫

Android 平台包含大量共享 Java 庫,可以選擇將這些 Java 庫包含在應用程序清單中帶有<uses-library>標記的應用程序的類路徑中。應用程序鏈接到這些庫,因此在兼容性、API 審查和工具支持方面將它們視為 Android API 的其餘部分。但是請注意,大多數庫都沒有這些功能。

java_sdk_library模塊類型有助於管理此類庫。設備製造商可以將這種機制用於他們自己的共享 Java 庫,以保持其 API 的向後兼容性。如果設備製造商通過<uses-library>標籤而不是 bootclass 路徑使用他們自己的共享 Java 庫, java_sdk_library可以驗證這些 Java 庫是 API 穩定的。

java_sdk_library實現了可供應用程序使用的可選 SDK API。通過構建文件 ( Android.bp ) 中的java_sdk_library實現的庫執行以下操作:

  • 生成的存根庫包括stubsstubs.systemstubs.test 。這些存根庫是通過識別@hide@SystemApi@TestApi註釋來創建的。
  • java_sdk_library管理 API 子目錄中的 API 規範文件(例如current.txt )。這些文件會根據最新代碼進行檢查,以確保它們是最新版本。如果不是,您會收到一條錯誤消息,說明如何更新它們。手動查看所有更新更改以確保它們符合您的期望。

    要更新所有 API,請使用m update-api 。要驗證 API 是否是最新的,請使用m checkapi
  • API 規範文件會根據最新發布的 Android 版本進行檢查,以確保 API 向後兼容早期版本。作為 AOSP 的一部分提供的java_sdk_library模塊將其先前發布的版本放置在prebuilts/sdk/<latest number>中。
  • 對於 API 規範文件檢查,您可以執行以下三件事之一
    • 允許檢查繼續進行。 (不要做任何事情。)
    • 通過將以下內容添加到java_sdk_library來禁用檢查:
      unsafe_ignore_missing_latest_api: true,
    • 通過在version/scope/api目錄中創建名為module_name.txt的空文本文件,為新的java_sdk_library模塊提供空 API。
  • 如果安裝了運行時的實現庫,則會生成並安裝一個 XML 文件。

java_sdk_library 的工作原理

名為Xjava_sdk_library創建以下內容:

  1. 實現庫的兩個副本:一個名為X的庫和另一個名為X.impl的庫。庫X安裝在設備上。庫X.impl僅在其他模塊需要對實現庫的顯式訪問時才存在,例如用於測試。請注意,很少需要顯式訪問。
  2. 可以啟用和禁用範圍以自定義訪問。 (類似於 Java 關鍵字訪問修飾符,公共範圍提供廣泛的訪問權限;測試範圍包含僅用於測試的 API。)對於每個啟用的範圍,庫創建以下內容:
    • 存根源模塊( droidstubs模塊類型) - 使用實現源並輸出一組存根源以及 API 規範文件。
    • 存根庫( java_library模塊類型) - 是存根的編譯版本。用於編譯它的庫與提供給java_sdk_library的庫不同,這確保了實現細節不會洩漏到 API 存根中。
    • 如果您需要其他庫來編譯存根,請使用stub_only_libsstub_only_static_libs屬性來提供它們。

如果java_sdk_library被稱為“ X ”,並且被編譯為“ X ”,請始終以這種方式引用它並且不要修改它。構建將選擇適當的庫。為確保您擁有最合適的庫,請檢查您的存根以查看構建是否引入了錯誤。使用本指南進行任何必要的更正:

  • 通過查看命令行並檢查那裡列出的存根以確定您的範圍來驗證您是否有適當的庫:
    • 範圍太廣:依賴庫需要一定範圍的 API。但是您會看到庫中包含的 API 超出了該範圍,例如公共 API 中包含的系統 API。
    • 範圍太窄:依賴庫無法訪問所有必需的庫。例如,依賴庫需要使用系統 API,但獲取的是公共 API。這通常會導致編譯錯誤,因為缺少所需的 API。
  • 要修復庫,只需執行以下操作之一
    • 更改sdk_version以選擇您需要的版本。或者
    • 顯式指定適當的庫,例如<X>.stubs<X>.stubs.system

java_sdk_library X 用法

當從apex.java_libs引用實現庫X時,它會被使用。但是,由於 Soong 的限制,當從同一個 APEX 庫中的另一個java_sdk_library模塊引用庫X時,必須明確使用X.impl而不是庫X

當從其他地方引用java_sdk_library時,將使用存根庫。根據依賴模塊的sdk_version屬性設置選擇存根庫。例如,指定sdk_version: "current"的模塊使用公共存根,而指定sdk_version: "system_current"的模塊使用系統存根。如果找不到完全匹配,則使用最近的存根庫。只提供公共 API 的java_sdk_library將為每個人提供公共存根。

使用 Java SDK 庫構建流程
圖 1.使用 Java SDK 庫的構建流程

示例和來源

srcsapi_packages屬性必須存在於java_sdk_library中。

java_sdk_library {
        name: "com.android.future.usb.accessory",
        srcs: ["src/**/*.java"],
        api_packages: ["com.android.future.usb"],
    }

AOSP 建議(但不要求)新的java_sdk_library實例顯式啟用他們想要使用的 API 範圍。您還可以(可選)遷移現有的java_sdk_library實例以顯式啟用它們將使用的 API 範圍:

java_sdk_library {
         name: "lib",
         public: {
           enabled: true,
         },
         system: {
           enabled: true,
         },
         …
    }

要配置用於運行時的impl庫,請使用所有正常的java_library屬性,例如hostdexcompile_dexerrorprone

java_sdk_library {
        name: "android.test.base",

        srcs: ["src/**/*.java"],

        errorprone: {
          javacflags: ["-Xep:DepAnn:ERROR"],
        },

        hostdex: true,

        api_packages: [
            "android.test",
            "android.test.suitebuilder.annotation",
            "com.android.internal.util",
            "junit.framework",
        ],

        compile_dex: true,
    }

要配置存根庫,請使用以下屬性:

  • merge_annotations_dirsmerge_inclusion_annotations_dirs
  • api_srcs :作為 API 一部分但不屬於運行時庫的可選源文件的列表。
  • stubs_only_libs :構建存根時類路徑中的 Java 庫列表。
  • hidden_api_packages :必須對 API 隱藏的包名稱列表。
  • droiddoc_optionsmetalava的附加參數。
  • droiddoc_option_files :列出可以使用$(location <label>)droiddoc_options中引用的文件,其中<file>是列表中的一個條目。
  • annotations_enabled

java_sdk_libraryjava_library ,但它不是droidstubs模塊,因此不支持所有droidstubs屬性。以下示例取自android.test.mock 庫構建文件。

java_sdk_library {
        name: "android.test.mock",

        srcs: [":android-test-mock-sources"],
        api_srcs: [
            // Note: The following aren’t APIs of this library. Only APIs under the
            // android.test.mock package are taken. These do provide private APIs
            // to which android.test.mock APIs reference. These classes are present
            // in source code form to access necessary comments that disappear when
            // the classes are compiled into a Jar library.
            ":framework-core-sources-for-test-mock",
            ":framework_native_aidl",
        ],

        libs: [
            "framework",
            "framework-annotations-lib",
            "app-compat-annotations",
            "Unsupportedappusage",
        ],

        api_packages: [
            "android.test.mock",
        ],
        permitted_packages: [
            "android.test.mock",
        ],
        compile_dex: true,
        default_to_stubs: true,
    }

保持向後兼容性

構建系統通過在構建時將最新的 API 文件與生成的 API 文件進行比較來檢查 API 是否保持向後兼容性。 java_sdk_library使用prebuilt_apis提供的信息執行兼容性檢查。所有使用java_sdk_library構建的庫都必須在prebuilt_apis中最新版本的api_dirs中有 API 文件。當您發布版本時,API 列表文件和存根庫可以通過 dist build 和PRODUCT=sdk_phone_armv7-sdk獲得。

api_dirs屬性是prebuilt_apis中 API 版本目錄的列表。 API 版本目錄必須位於Android.bp目錄級別。

prebuilt_apis {
       name: "foo",
       api_dirs: [
           "1",
           "2",
             ....
           "30",
           "current",
       ],
    }

配置prebuilts目錄下的version / scope /api/結構的目錄。 version對應於 API 級別, scope定義目錄是公共的、系統的還是測試的。

  • version / scope包含 Java 庫。
  • version / scope /api包含 API .txt文件。在此處創建名為module_name .txtmodule_name -removed.txt的空文本文件。
     ├── 30
          │   ├── public
          │   │   ├── api
          │   │   │   ├── android.test.mock-removed.txt
          │   │   │   └── android.test.mock.txt
          │   │   └── android.test.mock.jar
          │   ├── system
          │   │   ├── api
          │   │   │   ├── android.test.mock-removed.txt
          │   │   │   └── android.test.mock.txt
          │   │   └── android.test.mock.jar
          │   └── test
          │       ├── api
          │       │   ├── android.test.mock-removed.txt
          │       │   └── android.test.mock.txt
          │       └── android.test.mock.jar
          └── Android.bp