實作 Java SDK 程式庫

Android 平台包含大量共用的 Java 程式庫,您可以選擇在應用程式資訊清單中使用 <uses-library> 標記,將這些程式庫納入應用程式的 classpath。應用程式會連結至這些程式庫,因此請將這些程式庫視為其他 Android API,以相容性、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。這些 Stub 程式庫是透過辨識 @hide@SystemApi@TestApi 註解而建立。
  • java_sdk_library 會管理 API 子目錄中的 API 規格檔案 (例如 current.txt)。系統會根據最新程式碼檢查這些檔案,確保檔案為最新版本。如果不是,您會收到錯誤訊息,說明如何更新。手動檢查所有更新變更,確保這些變更符合您的預期。

    如要更新所有 API,請使用 m update-api。如要確認 API 是否為最新版本,請使用 m checkapi
  • 系統會根據最近發布的 Android 版本檢查 API 規格檔案,確保 API 與舊版相容。提供的 java_sdk_library 模組是 Android 開放原始碼計畫的一部分,會將先前發布的版本放入 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,請使用 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 的限制,如果程式庫 X 是從同一個 APEX 程式庫中的其他 java_sdk_library 模組參照,則必須使用明確的 X.impl,而非程式庫 X

java_sdk_library 從其他地方參照時,會使用 Stub 程式庫。系統會根據依附模組的 sdk_version 屬性設定,選取 Stub 程式庫。舉例來說,指定 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,
    }

如要設定 Stub 程式庫,請使用下列屬性:

  • 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 會列出檔案和 Stub 程式庫,您可以使用 PRODUCT=sdk_phone_armv7-sdk 進行 dist 建構來取得這些檔案。

api_dirs 屬性是 prebuilt_apis 中的 API 版本目錄清單。API 版本目錄必須位於 Android.bp 目錄層級。

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

在預先建構目錄下,使用 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