ART 服務設定

在開始之前,請先參閱 ART 服務的概要總覽。

自 Android 14 起,裝置端 AOT 編譯 應用程式 (又稱為 dexopt) 則由 ART 服務處理。ART 服務是 ART 的一部分 並透過系統屬性和 API 自訂模組。

系統屬性

ART 服務支援 dex2oat 選項

此外,ART 服務支援下列系統屬性:

pm.dexopt。<reason>

這組系統屬性會決定預設編譯器篩選器 Dexopt 情境中所述的所有預先定義編譯原因

若需更多資訊,請參閲 編譯器篩選器

標準預設值如下:

pm.dexopt.first-boot=verify
pm.dexopt.boot-after-ota=verify
pm.dexopt.boot-after-mainline-update=verify
pm.dexopt.bg-dexopt=speed-profile
pm.dexopt.inactive=verify
pm.dexopt.cmdline=verify

pm.dexopt.shared (預設值:速度)

這是適用於其他應用程式所用應用程式的備用編譯器篩選器。

原則上,ART 服務會進行設定檔引導編譯 (speed-profile),用於 所有應用程式。不過 其他應用程式使用的部分應用程式 (透過 <uses-library> 或已載入的應用程式) 方法是使用 Context#createPackageContextCONTEXT_INCLUDE_CODE)。這類應用程式無法使用本機 基於隱私權考量,影響個人資料或個人資料。

對於此類應用程式,如果要求設定檔引導編譯,ART 服務會先使用 嘗試使用雲端設定檔如果沒有雲端設定檔,ART Service 改回使用 pm.dexopt.shared 指定的編譯器篩選器。

如果要求的編譯作業並非設定檔指引,這個屬性就不會有任何作用。

pm.dexopt.<reason>.concurrency (預設值:1)

這是特定預先定義編譯作業的 dex2oat 叫用數量 原因 (first-bootboot-after-otaboot-after-mainline-updatebg-dexopt)。

請注意,這個選項的效果會與 dex2oat 資源用量選項 (dalvik.vm.*dex2oat-threadsdalvik.vm.*dex2oat-cpu-set 和工作設定檔):

  • dalvik.vm.*dex2oat-threads 控管每個 dex2oat 的執行緒數量 pm.dexopt.<reason>.concurrency 則控制 dex2oat 叫用。也就是說,並行執行緒數量上限為 這兩個系統屬性的乘積。
  • dalvik.vm.*dex2oat-cpu-set 和工作設定檔一律會繫結 CPU 核心 無論並行執行緒數量上限為何 (已討論) )。

單一 dex2oat 叫用可能無法完全使用所有 CPU 核心,無論如何 (共 dalvik.vm.*dex2oat-threads 個)。因此,提高 dex2oat 數量 叫用 (pm.dexopt.<reason>.concurrency) 就能更妥善地利用 CPU 核心,達到以下目的: 這能加快 dexopt 的整體進度這在 啟動。

不過,如果 dex2oat 叫用過多,可能會導致裝置 但可以透過將 dalvik.vm.dex2oat-swap 設為 true 允許使用替換檔案。叫用次數過多, 不需要切換環境因此,您應該仔細調整這個數字 按照各產品的需求分別處理

pm.dexopt.downGrade_after_inactive_days (預設:未設定)

如果設定這個選項,ART 服務只會使用最近指定的 天數。

此外,如果儲存空間即將用盡,在 dexopt 在背景執行 ART 服務 將未在前一個指定時間內未使用的應用程式降級 天數,以便釋出空間。這個問題的編譯器原因為 inactive。 編譯器篩選器則取決於 pm.dexopt.inactive聊天室 門檻是儲存空間管理工具的不足空間門檻 (可透過通用設定 sys_storage_threshold_percentagesys_storage_threshold_max_bytes,預設:500 MB) 再加上 500 MB。

如果透過 ArtManagerLocal#setBatchDexoptStartCallback,清單中提供的套件 bg-dexoptBatchDexoptStartCallback 指標絕不會降級。

pm.dexopt.disable_bg_dexopt (預設為 false)

僅供測試之用。這樣會防止 ART 服務安排背景排程 dexopt 工作

如果已安排背景執行 dexopt 工作,但尚未執行, 則不會有任何影響。也就是說,工作仍會執行。

避免背景 dexopt 工作 正在執行:

setprop pm.dexopt.disable_bg_dexopt true
pm bg-dexopt-job --disable

假如 尚未排定傳送時間第二行會解除背景 dexopt 工作排程 (如有) 且會立即取消背景 dexopt 工作 仍在執行中

ART 服務 API

ART 服務會公開 Java API 以進行自訂。API 的定義如下 ArtManagerLocal。如需 Java 文件,請參閱 art/libartservice/service/java/com/android/server/art/ArtManagerLocal.java: 使用情形 (Android 14 來源未發布的開發來源)。

ArtManagerLocalLocalManagerRegistry 保管的單例模式。助手 函式 com.android.server.pm.DexOptHelper#getArtManagerLocal 可協助您 第一。

import static com.android.server.pm.DexOptHelper.getArtManagerLocal;

大多數 API 都需要 PackageManagerLocal.FilteredSnapshot 的例項。 中存放了所有應用程式的資訊你可以前往「撥打」 PackageManagerLocal#withFilteredSnapshotPackageManagerLocal也是 由 LocalManagerRegistry 持有的單例模式,可從 com.android.server.pm.PackageManagerServiceUtils#getPackageManagerLocal

import static com.android.server.pm.PackageManagerServiceUtils.getPackageManagerLocal;

以下是一些 API 的一般用途。

針對應用程式觸發 dexopt 觸發程序

您可以隨時呼叫 ArtManagerLocal#dexoptPackage

try (var snapshot = getPackageManagerLocal().withFilteredSnapshot()) {
  getArtManagerLocal().dexoptPackage(
      snapshot,
      "com.google.android.calculator",
      new DexoptParams.Builder(ReasonMapping.REASON_INSTALL).build());
}

您也可以傳遞自己的 dexopt 原因。這時將由優先順序類別和 編譯器篩選器必須明確設定

try (var snapshot = getPackageManagerLocal().withFilteredSnapshot()) {
  getArtManagerLocal().dexoptPackage(
      snapshot,
      "com.google.android.calculator",
      new DexoptParams.Builder("my-reason")
          .setCompilerFilter("speed-profile")
          .setPriorityClass(ArtFlags.PRIORITY_BACKGROUND)
          .build());
}

取消 dexopt

如果作業是由 dexoptPackage 呼叫啟動,您可以傳遞 表示您可以在某個時間點取消作業這可以 以非同步方式執行 dexopt 時

Executor executor = ...;  // Your asynchronous executor here.
var cancellationSignal = new CancellationSignal();
executor.execute(() -> {
  try (var snapshot = getPackageManagerLocal().withFilteredSnapshot()) {
    getArtManagerLocal().dexoptPackage(
        snapshot,
        "com.google.android.calculator",
        new DexoptParams.Builder(ReasonMapping.REASON_INSTALL).build(),
        cancellationSignal);
  }
});

// When you want to cancel the operation.
cancellationSignal.cancel();

您也可以取消 ART 服務啟動的背景 dexopt。

getArtManagerLocal().cancelBackgroundDexoptJob();

取得 dexopt 結果

如果作業是由 dexoptPackage 呼叫啟動,您就可以取得結果 傳回的值

DexoptResult result;
try (var snapshot = getPackageManagerLocal().withFilteredSnapshot()) {
  result = getArtManagerLocal().dexoptPackage(...);
}

// Process the result here.
...

在許多情況下,ART 服務也會自行啟動 dexopt 作業,例如: 背景 dexopt。如要監聽所有 dexopt 結果,無論是否執行這項作業 由 dexoptPackage 呼叫或 ART 服務發起,請使用 ArtManagerLocal#addDexoptDoneCallback

getArtManagerLocal().addDexoptDoneCallback(
    false /* onlyIncludeUpdates */,
    Runnable::run,
    (result) -> {
      // Process the result here.
      ...
    });

第一個引數會決定是否只包含結果更新。如果 您只想監聽 dexopt 更新的套件,請將其設為 true。

第二個引數是回呼的執行程式。如要在 執行 dexopt 的相同執行緒,請使用 Runnable::run。如果您不想 回呼封鎖 dexopt,請使用非同步執行程式。

您可以新增多個回呼,讓 ART 服務執行所有回呼 所有回呼都將繼續運作,以供日後所有呼叫使用,除非 選擇移除

如要移除回呼,請在執行以下動作時保留回呼的參考資料: 新增,並使用 ArtManagerLocal#removeDexoptDoneCallback

DexoptDoneCallback callback = (result) -> {
  // Process the result here.
  ...
};

getArtManagerLocal().addDexoptDoneCallback(
    false /* onlyIncludeUpdates */, Runnable::run, callback);

// When you want to remove it.
getArtManagerLocal().removeDexoptDoneCallback(callback);

自訂套件清單和 dexopt 參數

ART 服務會在啟動和背景自行啟動 dexopt 作業 dexopt。如要自訂這些作業的套件清單或 dexopt 參數,請 使用 ArtManagerLocal#setBatchDexoptStartCallback

getArtManagerLocal().setBatchDexoptStartCallback(
    Runnable::run,
    (snapshot, reason, defaultPackages, builder, cancellationSignal) -> {
      switch (reason) {
        case ReasonMapping.REASON_BG_DEXOPT:
          var myPackages = new ArrayList<String>(defaultPackages);
          myPackages.add(...);
          myPackages.remove(...);
          myPackages.sort(...);
          builder.setPackages(myPackages);
          break;
        default:
          // Ignore unknown reasons.
      }
    });

你可以將商品加入包裹清單、移除項目、排序, 使用完全不同的清單

您的回呼必須忽略未知的原因,因為 未來的發展方向

最多只能設定一個BatchDexoptStartCallback。回呼會保留 。

如要清除回呼,請使用 ArtManagerLocal#clearBatchDexoptStartCallback

getArtManagerLocal().clearBatchDexoptStartCallback();

自訂背景 dexopt 工作的參數

根據預設,在裝置處於閒置狀態時,背景 dexopt 工作每天會執行一次 以及充電此功能可透過以下方式變更: ArtManagerLocal#setScheduleBackgroundDexoptJobCallback

getArtManagerLocal().setScheduleBackgroundDexoptJobCallback(
    Runnable::run,
    builder -> {
      builder.setPeriodic(TimeUnit.DAYS.toMillis(2));
    });

最多只能設定一個ScheduleBackgroundDexoptJobCallback。回呼會 。除非你清除密碼,否則日後所有通話都將保持啟用狀態。

如要清除回呼,請使用 ArtManagerLocal#clearScheduleBackgroundDexoptJobCallback

getArtManagerLocal().clearScheduleBackgroundDexoptJobCallback();

暫時停用 dexopt

凡是由 ART 服務啟動的 dexopt 作業,都會觸發 BatchDexoptStartCallback。只要您持續取消作業, 有效地停用 dexopt。

如果是取消背景 dexopt 的作業,則請遵循預設 重試政策 (30 秒,以指數表示,上限 5 小時)。

// Good example.

var shouldDisableDexopt = new AtomicBoolean(false);

getArtManagerLocal().setBatchDexoptStartCallback(
    Runnable::run,
    (snapshot, reason, defaultPackages, builder, cancellationSignal) -> {
      if (shouldDisableDexopt.get()) {
        cancellationSignal.cancel();
      }
    });

// Disable dexopt.
shouldDisableDexopt.set(true);
getArtManagerLocal().cancelBackgroundDexoptJob();

// Re-enable dexopt.
shouldDisableDexopt.set(false);

您最多只能有一個BatchDexoptStartCallback。如果您也想使用 BatchDexoptStartCallback 用於自訂套件清單或 dexopt 參數, 必須將程式碼合併為一個回呼。

// Bad example.

// Disable dexopt.
getArtManagerLocal().unscheduleBackgroundDexoptJob();

// Re-enable dexopt.
getArtManagerLocal().scheduleBackgroundDexoptJob();

在應用程式安裝時執行的 dexopt 作業「不是」ART 啟動 售後服務而是由套件管理員透過 dexoptPackage 呼叫。因此「不會」觸發動作 BatchDexoptStartCallback。如要停用應用程式安裝時的 dexopt,請防止 呼叫 dexoptPackage 的套件管理工具。

覆寫特定套件 (Android 15 以上版本) 的編譯器篩選器

您可以註冊 回呼 setAdjustCompilerFilterCallback。系統會呼叫回呼 每當 dexopt 啟動 在啟動和背景 dexopt 或 dexoptPackage API 呼叫期間的 ART 服務。

如果套件不需要調整,回呼必須傳回 originalCompilerFilter

getArtManagerLocal().setAdjustCompilerFilterCallback(
    Runnable::run,
    (packageName, originalCompilerFilter, reason) -> {
      if (isVeryImportantPackage(packageName)) {
        return "speed-profile";
      }
      return originalCompilerFilter;
    });

您只能設定一個AdjustCompilerFilterCallback。如要使用 AdjustCompilerFilterCallback 用於覆寫多個版本的編譯器篩選器 套件,您必須將程式碼合併為一個回呼。回呼會保留 。

如要清除回呼,請使用 ArtManagerLocal#clearAdjustCompilerFilterCallback

getArtManagerLocal().clearAdjustCompilerFilterCallback();

其他自訂項目

ART 服務也支援其他某些自訂設定。

設定背景 dexopt 的熱閾值

背景 dexopt 工作的熱控制是由工作排程器執行。 並在溫度達到上限時立即取消工作 THERMAL_STATUS_MODERATE。如果 「THERMAL_STATUS_MODERATE」可調整。

判斷 dexopt 是否正在執行 dexopt 背景

背景 dexopt 工作由 Job Scheduler 管理,其工作 ID 為 27873780。如要判斷工作是否正在執行,請使用 Job Scheduler API。

// Good example.

var jobScheduler =
    Objects.requireNonNull(mContext.getSystemService(JobScheduler.class));
int reason = jobScheduler.getPendingJobReason(27873780);

if (reason == PENDING_JOB_REASON_EXECUTING) {
  // Do something when the job is running.
  ...
}
// Bad example.

var backgroundDexoptRunning = new AtomicBoolean(false);

getArtManagerLocal().setBatchDexoptStartCallback(
    Runnable::run,
    (snapshot, reason, defaultPackages, builder, cancellationSignal) -> {
      if (reason.equals(ReasonMapping.REASON_BG_DEXOPT)) {
        backgroundDexoptRunning.set(true);
      }
    });

getArtManagerLocal().addDexoptDoneCallback(
    false /* onlyIncludeUpdates */,
    Runnable::run,
    (result) -> {
      if (result.getReason().equals(ReasonMapping.REASON_BG_DEXOPT)) {
        backgroundDexoptRunning.set(false);
      }
    });

if (backgroundDexoptRunning.get()) {
  // Do something when the job is running.
  ...
}

提供 dexopt 的設定檔

如要使用設定檔引導 dexopt,請將 .prof 檔案或 .dm 檔案放在 APK。

.prof 檔案必須是二進位格式設定檔,且檔案名稱必須 APK 檔案名稱 + .prof。例如:

base.apk.prof

.dm 檔案的檔案名稱必須是 擴充功能已由 .dm 取代。例如:

base.dm

如要驗證設定檔是否用於 dexopt,請使用下列指令執行 dexopt 指令 請speed-profile並查看結果。

pm art clear-app-profiles <package-name>
pm compile -m speed-profile -f -v <package-name>

第一行會清除執行階段產生的所有設定檔 (也就是 /data/misc/profiles) (如果有的話),確保 APK 旁邊的設定檔 ART Service 可能使用的唯一設定檔。第二行執行 dexopt 呼叫 speed-profile,並傳遞 -v 來列印詳細結果。

如果使用設定檔,這個設定檔會顯示 actualCompilerFilter=speed-profile 結果。否則,您會看到 actualCompilerFilter=verify。例如:

DexContainerFileDexoptResult{dexContainerFile=/data/app/~~QR0fTV0UbDbIP1Su7XzyPg==/com.google.android.gms-LvusF2uARKOtBbcaPHdUtQ==/base.apk, primaryAbi=true, abi=x86_64, actualCompilerFilter=speed-profile, status=PERFORMED, dex2oatWallTimeMillis=4549, dex2oatCpuTimeMillis=14550, sizeBytes=3715344, sizeBeforeBytes=3715344}

ART 服務不使用設定檔的常見原因包括:

  • 設定檔的檔案名稱有誤,或是檔案不在 APK 旁邊。
  • 設定檔格式錯誤。
  • 設定檔與 APK 不符。(設定檔的總和檢查碼沒有 與 APK 中 .dex 檔案的總和檢查碼相符)。