Tạo và đo lường Hồ sơ cơ sở theo cách thủ công

Bạn nên sử dụng phương thức tự động tạo quy tắc cho hồ sơ bằng Thư viện Jetpack Macrobenchmark để không mất nhiều công sức tự tạo và tăng khả năng có thể mở rộng nói chung. Tuy nhiên, bạn vẫn có thể tạo và đo lường các quy tắc cho hồ sơ trong ứng dụng theo cách thủ công.

Xác định quy tắc cấu hình theo cách thủ công

Bạn có thể xác định quy tắc cấu hình theo cách thủ công trong ứng dụng hoặc mô-đun thư viện bằng cách tạo tệp có tên baseline-prof.txt nằm trong thư mục src/main. Đây chính là thư mục chứa tệp AndroidManifest.xml.

Tệp chỉ định một quy tắc trên mỗi dòng. Mỗi quy tắc thể hiện một mẫu cho các phương thức hoặc lớp trùng khớp trong ứng dụng hoặc thư viện mà bạn cần tối ưu hoá.

Cú pháp cho các quy tắc này là tập mẹ của định dạng hồ sơ ART (HRF) mà con người có thể đọc được khi sử dụng adb shell profman --dump-classes-and-methods. Cú pháp này tương tự như cú pháp cho phần mô tả và chữ ký, nhưng cho phép sử dụng ký tự đại diện để đơn giản hoá quá trình viết quy tắc.

Ví dụ sau đây cho thấy một số quy tắc của Hồ sơ cơ sở có trong thư viện Jetpack Compose:

HSPLandroidx/compose/runtime/ComposerImpl;->updateValue(Ljava/lang/Object;)V
HSPLandroidx/compose/runtime/ComposerImpl;->updatedNodeCount(I)I
HLandroidx/compose/runtime/ComposerImpl;->validateNodeExpected()V
PLandroidx/compose/runtime/CompositionImpl;->applyChanges()V
HLandroidx/compose/runtime/ComposerKt;->findLocation(Ljava/util/List;I)I
Landroidx/compose/runtime/ComposerImpl;

Cú pháp quy tắc

Các quy tắc này dùng một trong 2 biểu mẫu để nhắm mục tiêu phương thức hoặc lớp:

[FLAGS][CLASS_DESCRIPTOR]->[METHOD_SIGNATURE]

Quy tắc lớp sử dụng mẫu sau:

[CLASS_DESCRIPTOR]

Hãy xem bảng sau để biết nội dung mô tả chi tiết:

Cú pháp Nội dung mô tả
FLAGS Thể hiện ít nhất một trong các ký tự H, SP để cho biết phải gắn cờ cho phương thức này là Hot, Startup hay Post Startup (liên quan đến loại khởi động).

Phương thức có cờ H cho biết đây là phương thức "nóng", tức là phương thức này được gọi nhiều lần trong suốt vòng đời ứng dụng.

Phương thức có cờ S cho biết đây là phương thức được gọi trong khi khởi động.

Phương thức có cờ P cho biết đây là phương thức được gọi sau khi khởi động.

Một lớp có trong tệp này cho biết rằng lớp này được dùng trong khi khởi động và phải được phân bổ trước trong vùng nhớ khối xếp để tránh chi phí tải lớp. Trình tổng hợp ART sử dụng nhiều chiến lược tối ưu hoá, chẳng hạn như tổng hợp AOT của các phương pháp này và thực hiện tối ưu hoá bố cục trong tệp AOT đã tạo.
CLASS_DESCRIPTOR Phần mô tả cho lớp của phương pháp nhắm mục tiêu. Ví dụ: androidx.compose.runtime.SlotTable có phần mô tả là Landroidx/compose/runtime/SlotTable;. L được thêm vào đây ở định dạng có thể thực thi Dalvik (DEX).
METHOD_SIGNATURE Chữ ký của phương thức, bao gồm cả tên, loại thông số và các kiểu dữ liệu trả về của phương thức. Ví dụ:

// LayoutNode.kt

fun isPlaced():Boolean {
// ...
}

trên LayoutNode có chữ ký isPlaced()Z.

Những mẫu này có thể có ký tự đại diện để có một quy tắc duy nhất bao gồm nhiều phương thức hoặc nhiều lớp. Để được hỗ trợ hướng dẫn khi viết bằng cú pháp quy tắc trong Android Studio, hãy xem trình bổ trợ Hồ sơ cơ sở Android.

Ví dụ về quy tắc ký tự đại diện có thể có dạng như sau:

HSPLandroidx/compose/ui/layout/**->**(**)**

Các loại được hỗ trợ trong quy tắc Hồ sơ cơ sở

Quy tắc hồ sơ cơ sở hỗ trợ các loại sau. Để biết chi tiết về các loại này, hãy xem định dạng có thể thực thi Dalvik (DEX).

Ký tự Loại Nội dung mô tả
B byte Byte đã ký
C ký tự Điểm mã ký tự Unicode được mã hoá bằng UTF-16
D gấp đôi Giá trị dấu phẩy động có độ chính xác gấp đôi
F số thực dấu phẩy động Giá trị dấu phẩy động có độ chính xác đơn
I int Số nguyên
J dài Số nguyên dài
S ngắn Ký tên ngắn
V void Void
Z boolean Đúng hay sai
L (tên lớp) tham chiếu Một bản sao tên lớp

Ngoài ra, các thư viện có thể xác định các quy tắc được đóng gói trong cấu phần phần mềm AAR. Khi bạn tạo APK để thêm các cấu phần phần mềm này, các quy tắc sẽ được hợp nhất với nhau (tương tự như cách hợp nhất tệp kê khai) và được tổng hợp thành một hồ sơ ART nhị phân nhỏ gọn dành riêng cho APK.

ART tận dụng hồ sơ này khi APK được dùng trên các thiết bị để AOT biên dịch một tập con cụ thể của ứng dụng tại thời điểm cài đặt trên Android 9 (API cấp 28) hoặc Android 7 (API cấp 24) khi sử dụng ProfileInstaller.

Thu thập Hồ sơ cơ sở theo cách thủ công

Bạn có thể tạo thủ công một Hồ sơ cơ sở mà không cần thiết lập thư viện Macrobenchmark và tạo các chế độ tự động hoá giao diện người dùng cho các hành trình trọng yếu của người dùng. Mặc dù bạn nên dùng Macrobenchmark, nhưng không phải lúc nào cũng dùng được. Ví dụ: nếu đang sử dụng một hệ thống xây dựng không dựa trên Gradle, thì bạn không dùng được trình bổ trợ Gradle cho Hồ sơ cơ sở. Trong những trường hợp như vậy, bạn có thể thu thập thủ công các quy tắc trong Hồ sơ cơ sở. Việc này sẽ dễ dàng hơn rất nhiều nếu bạn dùng một thiết bị hoặc trình mô phỏng chạy API 34 trở lên. Mặc dù bạn vẫn có thể dùng các API cấp thấp hơn, nhưng bắt buộc phải có quyền truy cập gốc và bạn cần dùng một trình mô phỏng chạy hình ảnh AOSP (Dự án nguồn mở Android). Bạn có thể trực tiếp thu thập các quy tắc bằng cách làm như sau:

  1. Cài đặt một phiên bản phát hành cho ứng dụng của bạn trên thiết bị thử nghiệm. Loại bản dựng ứng dụng phải được tối ưu hoá cho R8 và là loại không thể gỡ lỗi để có một hồ sơ chính xác.
  2. Hãy đảm bảo rằng các hồ sơ chưa được biên dịch.

    API 34 trở lên

    adb shell cmd package compile -f -m verify $PACKAGE_NAME
    adb shell pm art clear-app-profiles $PACKAGE_NAME
    

    API 33 trở xuống

    adb root
    adb shell cmd package compile --reset $PACKAGE_NAME
    

    Nếu tệp APK của bạn có một phần phụ thuộc trong thư viện Trình cài đặt hồ sơ của Jetpack, thì thư viện sẽ khởi động một hồ sơ trong lần đầu khởi chạy tệp APK. Việc này có thể ảnh hưởng đến quá trình tạo hồ sơ, vì vậy, hãy tắt chế độ này bằng lệnh sau:

    adb shell am broadcast -a androidx.profileinstaller.action.SKIP_FILE $PACKAGE_NAME/androidx.profileinstaller.ProfileInstallReceiver
    

  3. Chạy ứng dụng và thao tác theo cách thủ công thông qua các hành trình trọng yếu của người dùng mà bạn muốn thu thập hồ sơ.
  4. Nhắc ART kết xuất hồ sơ. Nếu APK của bạn có một phần phụ thuộc trong thư viện Trình cài đặt hồ sơ của Jetpack, hãy sử dụng phần phụ thuộc đó để kết xuất hồ sơ:

    adb shell am broadcast -a androidx.profileinstaller.action.SAVE_FILE $PACKAGE_NAME/androidx.profileinstaller.ProfileInstallReceiver
    adb shell am force-stop $PACKAGE_NAME
    
    Nếu bạn không dùng Trình cài đặt hồ sơ, hãy kết xuất hồ sơ theo cách thủ công trên một trình mô phỏng bằng lệnh sau:

    adb root
    adb shell killall -s SIGUSR1 $PACKAGE_NAME
    adb shell am force-stop $PACKAGE_NAME
    

  5. Vui lòng đợi ít nhất 5 giây để quá trình tạo hồ sơ hoàn tất.
  6. Chuyển đổi các hồ sơ ở dạng tệp nhị phân tạo ra sang dạng văn bản:

    API 34 trở lên

    adb shell pm dump-profiles --dump-classes-and-methods $PACKAGE_NAME
    

    API 33 trở xuống

    Xác định xem đã tạo một hồ sơ tham chiếu hoặc hồ sơ hiện tại hay chưa. Hồ sơ tham chiếu nằm ở vị trí sau:

    /data/misc/profiles/ref/$$PACKAGE_NAME/primary.prof
    

    Hồ sơ hiện tại nằm ở vị trí sau:

    /data/misc/profiles/cur/0/$PACKAGE_NAME/primary.prof
    

    Xác định vị trí của APK:

    adb root
    adb shell pm path $PACKAGE_NAME
    

    Thực hiện việc chuyển đổi:

    adb root
    adb shell profman --dump-classes-and-methods --profile-file=$PROFILE_PATH --apk=$APK_PATH > /data/misc/profman/$PACKAGE_NAME-primary.prof.txt
    

  7. Sử dụng adb để truy xuất hồ sơ đã kết xuất từ thiết bị:

    adb pull /data/misc/profman/$PACKAGE_NAME-primary.prof.txt PATH_TO_APP_MODULE/src/main/
    

Hành động này sẽ lấy các quy tắc hồ sơ đã tạo và cài đặt chúng vào mô-đun ứng dụng của bạn. Vào lần tiếp theo bạn tạo ứng dụng này, Hồ sơ cơ sở sẽ được đưa vào. Hãy xác minh hành động này bằng cách làm theo các bước trong bài viết Vấn đề với việc cài đặt.

Đo lường thủ công mức độ cải thiện ứng dụng

Bạn nên đo lường mức độ cải thiện của ứng dụng thông qua tính năng đo điểm chuẩn. Tuy nhiên, nếu muốn tự đo lường mức độ cải thiện, bạn có thể bắt đầu bằng cách đo lường quá trình khởi động ứng dụng chưa được tối ưu hoá để tham chiếu.

PACKAGE_NAME=com.example.app
# Force Stop App
adb shell am force-stop $PACKAGE_NAME
# Reset compiled state
adb shell cmd package compile --reset $PACKAGE_NAME
# Measure App startup
# This corresponds to `Time to initial display` metric.
adb shell am start-activity -W -n $PACKAGE_NAME/.ExampleActivity \
 | grep "TotalTime"

Tiếp theo, hãy cài đặt Hồ sơ cơ sở không qua cửa hàng ứng dụng.

# Unzip the Release APK first.
unzip release.apk
# Create a ZIP archive.
# The name should match the name of the APK.
# Copy `baseline.prof{m}` and rename it `primary.prof{m}`.
cp assets/dexopt/baseline.prof primary.prof
cp assets/dexopt/baseline.profm primary.profm
# Create an archive.
zip -r release.dm primary.prof primary.profm
# Confirm that release.dm only contains the two profile files:
unzip -l release.dm
# Archive:  release.dm
#   Length      Date    Time    Name
# ---------  ---------- -----   ----
#      3885  1980-12-31 17:01   primary.prof
#      1024  1980-12-31 17:01   primary.profm
# ---------                     -------
#                               2 files
# Install APK + Profile together.
adb install-multiple release.apk release.dm

Để xác minh rằng gói đã được tối ưu hoá khi cài đặt, hãy chạy lệnh sau:

# Check dexopt state.
adb shell dumpsys package dexopt | grep -A 1 $PACKAGE_NAME

Kết quả phải cho biết gói được biên dịch:

[com.example.app]
  path: /data/app/~~YvNxUxuP2e5xA6EGtM5i9A==/com.example.app-zQ0tkJN8tDrEZXTlrDUSBg==/base.apk
  arm64: [status=speed-profile] [reason=install-dm]

Giờ đây, bạn có thể đo lường hiệu suất khi khởi động ứng dụng như trước đây mà không cần đặt lại trạng thái đã biên dịch. Lưu ý: Đảm bảo rằng bạn không đặt lại trạng thái tổng hợp của gói.

# Force stop app
adb shell am force-stop $PACKAGE_NAME
# Measure app startup
adb shell am start-activity -W -n $PACKAGE_NAME/.ExampleActivity \
 | grep "TotalTime"

Hồ sơ cơ sở và profgen

Phần này mô tả chức năng của công cụ profgen khi tạo một phiên bản nhị phân nhỏ gọn của một Hồ sơ cơ sở.

Profgen-cli hỗ trợ biên dịch, truy vấn và chuyển đổi mã nguồn cho hồ sơ ART để các hồ sơ này có thể được cài đặt trên những thiết bị chạy Android bất kể phiên bản SDK mục tiêu.

Profgen-cli là một CLI biên dịch HRF của Hồ sơ cơ sở thành định dạng được biên dịch. CLI cũng xuất trong kho lưu trữ cmdline-tools như một phần của SDK Android.

Các tính năng này có trong nhánh studio-main:

➜ ../cmdline-tools/latest/bin
apkanalyzer
avdmanager
lint
profgen
retrace
screenshot2
sdkmanager

Xây dựng hồ sơ nhỏ gọn ở dạng tệp nhị phân bằng Profgen-cli

Các lệnh dùng được với Profgen-cli là bin, validatedumpProfile. Để xem các lệnh hiện có, hãy dùng profgen --help:

profgen --help
Usage: profgen options_list
Subcommands:
    bin - Generate Binary Profile
    validate - Validate Profile
    dumpProfile - Dump a binary profile to a HRF

Options:
    --help, -h -> Usage info

Dùng lệnh bin để tạo hồ sơ nhị phân nhỏ gọn. Sau đây là ví dụ về lệnh gọi:

profgen bin ./baseline-prof.txt \
  --apk ./release.apk \
  --map ./obfuscation-map.txt \
  --profile-format v0_1_0_p \
  --output ./baseline.prof \

Để xem các tuỳ chọn có sẵn, hãy dùng lệnh profgen bin options_list:

Usage: profgen bin options_list
Arguments:
    profile -> File path to Human Readable profile { String }
Options:
    --apk, -a -> File path to apk (always required) { String }
    --output, -o -> File path to generated binary profile (always required)
    --map, -m -> File path to name obfuscation map { String }
    --output-meta, -om -> File path to generated metadata output { String }
    --profile-format, -pf [V0_1_0_P] -> The ART profile format version
      { Value should be one of [
         v0_1_5_s, v0_1_0_p, v0_0_9_omr1, v0_0_5_o, v0_0_1_n
        ]
      }
    --help, -h -> Usage info

Đối số đầu tiên biểu thị đường dẫn đến HRF baseline-prof.txt.

Profgen-cli cũng cần đường dẫn đến bản phát hành của tệp APK và một bản đồ làm rối mã nguồn dùng để làm rối mã nguồn của APK khi sử dụng R8 hoặc Proguard. Bằng cách này, profgen có thể dịch các biểu tượng nguồn trong HRF sang tên bị làm rối tương ứng khi tạo hồ sơ đã biên dịch.

Vì các định dạng hồ sơ ART không tương thích ngược hoặc xuôi, hãy cung cấp một định dạng hồ sơ để profgen gói siêu dữ liệu hồ sơ (profm) mà bạn có thể dùng để chuyển mã của một định dạng hồ sơ ART sang một định dạng khác khi cần.

Định dạng hồ sơ và phiên bản nền tảng

Có các tuỳ chọn sau đây khi chọn một định dạng hồ sơ:

Định dạng hồ sơ Phiên bản nền tảng Cấp độ API
v0_1_5_s Android S+ Ít nhất 31
v0_1_0_p Android P, Q và R 28-30
v0_0_9_omr1 Android O MR1 27
v0_0_5_o Android O 26
v0_0_1_n Android N 24-25

Sao chép các tệp đầu ra baseline.profbaseline.profm vào thư mục assets hoặc dexopt trong APK.

Bản đồ làm rối mã nguồn

Bạn chỉ cần cung cấp bản đồ làm rối mã nguồn nếu HRF sử dụng ký hiệu nguồn. Nếu HRF được tạo từ một bản phát hành đã bị làm rối mã nguồn và không cần liên kết, bạn có thể bỏ qua tuỳ chọn đó rồi sao chép các kết quả vào thư mục assets hoặc dexopt.

Cài đặt Hồ sơ cơ sở theo cách thông thường

Hồ sơ cơ sở thường được phân phối đến thiết bị theo một trong 2 cách.

Dùng install-multiple với DexMetadata

Trên các thiết bị chạy API 28 trở lên, ứng dụng Play sẽ tải xuống tải trọng (payload) APK và DexMetadata (DM) cho phiên bản APK đang cài đặt. DM chứa thông tin hồ sơ được chuyển đến Trình quản lý gói trên thiết bị.

APK và DM được cài đặt trong một phiên cài đặt duy nhất bằng cách dùng các tệp như:

adb install-multiple base.apk base.dm

Jetpack ProfileInstaller

Trên các thiết bị chạy API cấp 29 trở lên, thư viện Jetpack ProfileInstaller cung cấp một cơ chế thay thế để cài đặt một hồ sơ được gói vào assetshoặc dexopt sau khi APK được cài đặt trên thiết bị. ProfileInstaller được ProfileInstallReceiver hoặc ứng dụng gọi trực tiếp.

Thư viện ProfileInstaller chuyển mã hồ sơ dựa trên phiên bản SDK của thiết bị mục tiêu và sao chép hồ sơ đó vào thư mục cur trên thiết bị (một thư mục thử nghiệm dành riêng cho gói cho các hồ sơ ART trên thiết bị).

Khi thiết bị ở trạng thái rảnh, hồ sơ sẽ được tiếp nhận bằng một quy trình có tên là bg-dexopt trên thiết bị.

Cài đặt Hồ sơ cơ sở không qua cửa hàng

Phần này mô tả cách cài đặt Hồ sơ cơ sở dựa vào một APK.

Truyền tin bằng androidx.profileinstaller

Trên các thiết bị chạy API 24 trở lên, bạn có thể truyền một lệnh để cài đặt hồ sơ:

# Broadcast the install profile command - moves binary profile from assets
#     to a location where ART uses it for the next compile.
#     When successful, the following command prints "1":
adb shell am broadcast \
    -a androidx.profileinstaller.action.INSTALL_PROFILE \
    <pkg>/androidx.profileinstaller.ProfileInstallReceiver

# Kill the process
am force-stop <pkg>

# Compile the package based on profile
adb shell cmd package compile -f -m speed-profile <pkg>

ProfileInstaller không có ở hầu hết các APK có Hồ sơ cơ sở (chỉ có trong khoảng 77 nghìn trong số 450 nghìn ứng dụng trên Play), mặc dù hồ sơ này hiện diện hiệu quả trong mọi APK sử dụng Compose. Điều này là do các thư viện có thể cung cấp hồ sơ mà không cần khai báo phần phụ thuộc trên ProfileInstaller. Việc thêm một phần phụ thuộc vào mỗi thư viện có hồ sơ sẽ áp dụng bắt đầu bằng Jetpack.

Sử dụng install-multiple với profgen hoặc DexMetaData

Trên các thiết bị chạy API 28 trở lên, bạn có thể cài đặt một Hồ sơ cơ sở không qua cửa hàng mà không cần phải có thư viện ProfileInstaller trong ứng dụng.

Để thực hiện việc này, hãy sử dụng Profgen-cli:

profgen extractProfile \
        --apk app-release.apk \
        --output-dex-metadata app-release.dm \
        --profile-format V0_1_5_S # Select based on device and the preceding table.

# Install APK and the profile together
adb install-multiple appname-release.apk appname-release.dm

Để hỗ trợ việc phân tách APK, hãy chạy các bước trích xuất hồ sơ trước đó một lần cho mỗi APK. Tại thời điểm cài đặt, hãy chuyển từng tệp APK và tệp .dm được liên kết, đảm bảo các tên APK và .dm khớp với nhau:

adb install-multiple appname-base.apk appname-base.dm \
appname-split1.apk appname-split1.dm

Xác minh

Để xác minh rằng hồ sơ đã được cài đặt đúng cách, bạn có thể sử dụng các bước trong phần Đo lường mức độ cải thiện của ứng dụng theo cách thủ công.

Kết xuất nội dung của hồ sơ nhị phân

Để xem xét nội dung cho một phiên bản nhị phân nhỏ gọn của Hồ sơ cơ sở, hãy sử dụng tuỳ chọn Profgen-cli dumpProfile:

Usage: profgen dumpProfile options_list
Options:
    --profile, -p -> File path to the binary profile (always required)
    --apk, -a -> File path to apk (always required) { String }
    --map, -m -> File path to name obfuscation map { String }
    --strict, -s [true] -> Strict mode
    --output, -o -> File path for the HRF (always required) { String }
    --help, -h -> Usage info

dumpProfile cần APK vì chế độ biểu diễn nhị phân nhỏ gọn chỉ lưu trữ độ lệch DEX. Do đó, bạn cần các APK này để tạo lại tên lớp và tên phương thức.

Chế độ nghiêm ngặt được bật theo mặc định và thực hiện việc kiểm tra khả năng tương thích của hồ sơ với các tệp DEX trong APK. Nếu đang cố gắng gỡ lỗi những hồ sơ do một công cụ khác tạo ra, thì bạn có thể sẽ gặp lỗi tương thích khiến bạn không thể kết xuất để nghiên cứu. Trong những trường hợp như vậy, bạn có thể tắt chế độ nghiêm ngặt bằng --strict false. Tuy nhiên, trong hầu hết các trường hợp, bạn nên bật chế độ nghiêm ngặt.

Bản đồ làm rối mã nguồn là không bắt buộc; khi được cung cấp, tuỳ chọn này sẽ giúp liên kết lại các biểu tượng bị làm rối với phiên bản dễ đọc để dễ sử dụng.