Triển khai thư viện SDK Java

Nền tảng Android chứa một lượng lớn thư viện Java dùng chung mà bạn có thể đưa vào đường dẫn lớp của ứng dụng bằng thẻ <uses-library> trong tệp kê khai ứng dụng. Các ứng dụng liên kết với các thư viện này, vì vậy, hãy coi chúng giống như phần còn lại của API Android về khả năng tương thích, xem xét API và hỗ trợ công cụ. Tuy nhiên, hãy lưu ý rằng hầu hết các thư viện đều không có các tính năng này.

Loại mô-đun java_sdk_library giúp quản lý các thư viện thuộc loại này. Các nhà sản xuất thiết bị có thể sử dụng cơ chế này cho các thư viện Java dùng chung của riêng họ để duy trì khả năng tương thích ngược cho các API của họ. Nếu nhà sản xuất thiết bị sử dụng thư viện Java dùng chung của riêng họ thông qua thẻ <uses-library> thay vì đường dẫn bootclass, thì java_sdk_library có thể xác minh rằng các thư viện Java đó có API ổn định.

java_sdk_library triển khai các API SDK không bắt buộc để các ứng dụng sử dụng. Các thư viện được triển khai thông qua java_sdk_library trong tệp bản dựng (Android.bp) thực hiện các thao tác sau:

  • Thư viện giả lập được tạo để bao gồm stubs, stubs.systemstubs.test. Các thư viện giả lập này được tạo bằng cách nhận dạng các chú thích @hide, @SystemApi@TestApi.
  • java_sdk_library quản lý các tệp thông số kỹ thuật API (chẳng hạn như current.txt) trong một thư mục con API. Các tệp này được kiểm tra dựa trên mã mới nhất để đảm bảo rằng đó là các phiên bản mới nhất. Nếu không, bạn sẽ nhận được thông báo lỗi giải thích cách cập nhật các tệp đó. Xem xét thủ công tất cả thay đổi đối với bản cập nhật để đảm bảo rằng các thay đổi đó phù hợp với mong đợi của bạn.

    Để cập nhật tất cả API, hãy sử dụng m update-api. Để xác minh rằng API đã được cập nhật, hãy sử dụng m checkapi.
  • Các tệp thông số kỹ thuật API được kiểm tra theo các phiên bản Android mới phát hành nhất để đảm bảo rằng API tương thích ngược với các bản phát hành trước đó. Các mô-đun java_sdk_library được cung cấp trong AOSP sẽ đặt các phiên bản đã phát hành trước đó vào prebuilts/sdk/<latest number>.
  • Đối với việc kiểm tra tệp đặc tả API, bạn có thể làm một trong ba việc sau:
    • Cho phép tiếp tục kiểm tra. (Không làm gì cả.)
    • Tắt tính năng kiểm tra bằng cách thêm nội dung sau vào java_sdk_library:
      unsafe_ignore_missing_latest_api: true,
    • Cung cấp API trống cho các mô-đun java_sdk_library mới bằng cách tạo các tệp văn bản trống có tên module_name.txt trong thư mục version/scope/api.
  • Nếu thư viện triển khai cho thời gian chạy được cài đặt, thì tệp XML sẽ được tạo và cài đặt.

Cách hoạt động của java_sdk_library

java_sdk_library có tên là X sẽ tạo ra những nội dung sau:

  1. Hai bản sao của thư viện triển khai: một thư viện có tên X và một thư viện khác có tên X.impl. Thư viện X được cài đặt trên thiết bị. Thư viện X.impl chỉ xuất hiện nếu các mô-đun khác cần quyền truy cập rõ ràng vào thư viện triển khai, chẳng hạn như để sử dụng trong kiểm thử. Xin lưu ý rằng bạn hiếm khi cần quyền truy cập rõ ràng.
  2. Bạn có thể bật và tắt phạm vi để tuỳ chỉnh quyền truy cập. (Tương tự như các công cụ sửa đổi quyền truy cập từ khoá Java, phạm vi công khai cung cấp nhiều quyền truy cập; phạm vi kiểm thử chứa các API chỉ dùng trong kiểm thử.) Đối với mỗi phạm vi đã bật, thư viện sẽ tạo những mục sau:
    • Mô-đun nguồn giả lập (loại mô-đun droidstubs) – sử dụng nguồn triển khai và xuất một tập hợp các nguồn giả lập cùng với tệp thông số kỹ thuật API.
    • Thư viện giả lập (loại mô-đun java_library) – là phiên bản đã biên dịch của các mô-đun giả lập. Các thư viện dùng để biên dịch mã này không giống với các thư viện được cung cấp cho java_sdk_library, giúp đảm bảo thông tin chi tiết về quá trình triển khai không bị rò rỉ vào các mã giả lập API.
    • Nếu bạn cần thêm thư viện để biên dịch các mã giả lập, hãy sử dụng thuộc tính stub_only_libsstub_only_static_libs để cung cấp các thư viện đó.

Nếu java_sdk_library được gọi là "X" và đang được biên dịch thành "X", hãy luôn tham chiếu đến java_sdk_library theo cách đó và không sửa đổi java_sdk_library. Bản dựng sẽ chọn một thư viện phù hợp. Để đảm bảo rằng bạn có thư viện phù hợp nhất, hãy kiểm tra các mã giả lập để xem bản dựng có gây ra lỗi hay không. Hãy chỉnh sửa những điểm cần thiết theo hướng dẫn sau:

  • Xác minh rằng bạn có một thư viện phù hợp bằng cách xem dòng lệnh và kiểm tra xem có mã giả lập nào được liệt kê ở đó để xác định phạm vi của bạn hay không:
    • Phạm vi quá rộng: Thư viện phụ thuộc cần một phạm vi API nhất định. Tuy nhiên, bạn sẽ thấy các API có trong thư viện nằm ngoài phạm vi đó, chẳng hạn như các API hệ thống đi kèm với API công khai.
    • Phạm vi quá hẹp: Thư viện phụ thuộc không có quyền truy cập vào tất cả thư viện cần thiết. Ví dụ: thư viện phụ thuộc cần sử dụng API hệ thống nhưng lại nhận được API công khai. Điều này thường dẫn đến lỗi biên dịch vì thiếu các API cần thiết.
  • Để khắc phục thư viện, bạn chỉ cần làm một trong những việc sau:
    • Thay đổi sdk_version để chọn phiên bản bạn cần. HOẶC
    • Chỉ định rõ ràng thư viện thích hợp, chẳng hạn như <X>.stubs hoặc <X>.stubs.system.

Cách sử dụng java_sdk_library X

Thư viện triển khai X được sử dụng khi được tham chiếu từ apex.java_libs. Tuy nhiên, do giới hạn của Soong, khi thư viện X được tham chiếu từ một mô-đun java_sdk_library khác trong cùng thư viện APEX, bạn phải sử dụng X.impl một cách rõ ràng, chứ không phải thư viện X.

Khi java_sdk_library được tham chiếu từ nơi khác, thư viện stubs sẽ được sử dụng. Thư viện giả lập được chọn theo chế độ cài đặt thuộc tính sdk_version của mô-đun phụ thuộc. Ví dụ: một mô-đun chỉ định sdk_version: "current" sử dụng các mã giả công khai, trong khi một mô-đun chỉ định sdk_version: "system_current" sử dụng các mã giả hệ thống. Nếu không tìm thấy kết quả trùng khớp chính xác, thư viện giả lập gần nhất sẽ được sử dụng. java_sdk_library chỉ cung cấp API công khai sẽ cung cấp các mã giả công khai cho mọi người.

Xây dựng quy trình bằng thư viện SDK Java
Hình 1. Quy trình xây dựng bằng thư viện SDK Java

Ví dụ và nguồn

Thuộc tính srcsapi_packages phải có trong java_sdk_library.

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

AOSP đề xuất (nhưng không bắt buộc) các thực thể java_sdk_library mới bật rõ ràng các phạm vi API mà chúng muốn sử dụng. Bạn cũng có thể (không bắt buộc) di chuyển các thực thể java_sdk_library hiện có để bật rõ ràng các phạm vi API mà chúng sẽ sử dụng:

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

Để định cấu hình thư viện impl dùng cho thời gian chạy, hãy sử dụng tất cả các thuộc tính java_library thông thường, chẳng hạn như hostdex, compile_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,
    }

Để định cấu hình thư viện giả lập, hãy sử dụng các thuộc tính sau:

  • merge_annotations_dirsmerge_inclusion_annotations_dirs.
  • api_srcs: Danh sách các tệp nguồn không bắt buộc thuộc API nhưng không thuộc thư viện thời gian chạy.
  • stubs_only_libs: Danh sách các thư viện Java có trong đường dẫn lớp khi tạo mã giả lập.
  • hidden_api_packages: Danh sách tên gói phải được ẩn khỏi API.
  • droiddoc_options: Đối số bổ sung cho metalava.
  • droiddoc_option_files: Liệt kê các tệp có thể được tham chiếu từ trong droiddoc_options bằng $(location <label>), trong đó <file> là một mục trong danh sách.
  • annotations_enabled.

java_sdk_libraryjava_library, nhưng không phải là mô-đun droidstubs, do đó không hỗ trợ tất cả thuộc tính droidstubs. Ví dụ sau được lấy từ tệp bản dựng thư viện 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,
    }

Duy trì khả năng tương thích ngược

Hệ thống xây dựng sẽ kiểm tra xem các API có duy trì khả năng tương thích ngược hay không bằng cách so sánh các tệp API mới nhất với các tệp API được tạo tại thời điểm tạo bản dựng. java_sdk_library thực hiện kiểm tra khả năng tương thích bằng thông tin do prebuilt_apis cung cấp. Tất cả thư viện được tạo bằng java_sdk_library phải có tệp API trong phiên bản mới nhất của api_dirs trong prebuilt_apis. Khi bạn phát hành phiên bản, API sẽ liệt kê các tệp và thư viện giả lập có thể được lấy bằng bản dựng dist với PRODUCT=sdk_phone_armv7-sdk.

Thuộc tính api_dirs là danh sách các thư mục phiên bản API trong prebuilt_apis. Các thư mục phiên bản API phải nằm ở cấp thư mục Android.bp.

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

Định cấu hình các thư mục bằng cấu trúc version/scope/api/ trong thư mục tạo sẵn. version tương ứng với cấp độ API và scope xác định xem thư mục đó là công khai, hệ thống hay kiểm thử.

  • version/scope chứa các thư viện Java.
  • version/scope/api chứa các tệp API .txt. Tạo các tệp văn bản trống có tên module_name.txtmodule_name-removed.txt tại đây.
     ├── 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