پیکربندی سرویس ART

قبل از شروع، یک نمای کلی سطح بالا از سرویس ART را ببینید.

با شروع Android 14، کامپایل AOT روی دستگاه برای برنامه‌ها (معروف به dexopt) توسط سرویس ART انجام می‌شود. سرویس ART بخشی از ماژول ART است و می توانید آن را از طریق ویژگی های سیستم و API ها سفارشی کنید.

ویژگی های سیستم

سرویس ART از تمام گزینه های مربوطه dex2oat پشتیبانی می کند.

علاوه بر این، ART Service از ویژگی های سیستم زیر پشتیبانی می کند:

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 Service کامپایل هدایت‌شده پروفایل ( speed-profile ) را برای همه برنامه‌ها در صورت امکان انجام می‌دهد، معمولاً در هنگام پس‌زمینه dexopt. با این حال، برخی از برنامه‌ها هستند که توسط برنامه‌های دیگر استفاده می‌شوند (از طریق <uses-library> یا به صورت پویا با استفاده از Context#createPackageContext با CONTEXT_INCLUDE_CODE بارگیری می‌شوند). چنین برنامه هایی به دلایل حفظ حریم خصوصی نمی توانند از نمایه های محلی استفاده کنند.

برای چنین برنامه‌ای، اگر تلفیقی با هدایت نمایه درخواست شود، سرویس ART ابتدا سعی می‌کند از نمایه ابری استفاده کند. اگر نمایه ابری وجود نداشته باشد، سرویس ART دوباره از فیلتر کامپایلر مشخص شده توسط pm.dexopt.shared استفاده می کند.

اگر کامپایل درخواستی با نمایه هدایت نشده باشد، این ویژگی تاثیری ندارد.

pm.dexopt.<reason>.concurrency (پیش‌فرض: 1)

این تعداد فراخوانی‌های dex2oat به دلایل کامپایل‌سازی از پیش تعریف‌شده ( first-boot ، boot-after-ota ، boot-after-mainline-update ، و bg-dexopt ) است.

توجه داشته باشید که اثر این گزینه با گزینه‌های استفاده از منابع dex2oat ( dalvik.vm.*dex2oat-threads ، dalvik.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 برای اجازه استفاده از فایل swap، آن را کاهش داد. فراخوان‌های زیاد نیز ممکن است باعث تغییر متن غیر ضروری شود. بنابراین، این عدد باید بر اساس محصول به محصول به دقت تنظیم شود.

pm.dexopt.downgrade_after_inactive_days (پیش‌فرض: تنظیم نشده)

اگر این گزینه تنظیم شده باشد، سرویس ART فقط برنامه‌های مورد استفاده در آخرین تعداد روز معین را حذف می‌کند.

علاوه بر این، اگر فضای ذخیره‌سازی تقریباً کم باشد، در طول Dexopt پس‌زمینه، ART Service فیلتر کامپایلر برنامه‌هایی را که در چند روز گذشته استفاده نشده‌اند، کاهش می‌دهد تا فضا آزاد شود. دلیل کامپایلر برای این inactive است و فیلتر کامپایلر توسط pm.dexopt.inactive تعیین می شود. آستانه فضایی برای فعال کردن این ویژگی، آستانه فضای کم Storage Manager (قابل تنظیم از طریق تنظیمات جهانی sys_storage_threshold_percentage و sys_storage_threshold_max_bytes ، پیش‌فرض: 500 مگابایت) به اضافه 500 مگابایت است.

اگر لیست بسته ها را از طریق ArtManagerLocal#setBatchDexoptStartCallback سفارشی کنید، بسته های موجود در لیست ارائه شده توسط BatchDexoptStartCallback برای bg-dexopt هرگز تنزل داده نمی شوند.

pm.dexopt.disable_bg_dexopt (پیش‌فرض: نادرست)

این فقط برای آزمایش است. از برنامه ریزی ART Service برای Dexopt پس زمینه جلوگیری می کند.

اگر کار dexopt پس‌زمینه قبلاً برنامه‌ریزی شده است اما هنوز اجرا نشده است، این گزینه تأثیری ندارد. یعنی کار همچنان ادامه خواهد داشت.

دنباله ای از دستورات توصیه شده برای جلوگیری از اجرای کار پس زمینه dexopt عبارتند از:

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

خط اول از برنامه ریزی کار پس زمینه dexopt جلوگیری می کند، اگر هنوز برنامه ریزی نشده باشد. خط دوم کار dexopt پس‌زمینه را از زمان‌بندی خارج می‌کند، اگر از قبل برنامه‌ریزی شده باشد، و بلافاصله کار dexopt پس‌زمینه را لغو می‌کند، اگر در حال اجرا باشد.

API های سرویس ART

سرویس ART API های جاوا را برای سفارشی سازی در معرض نمایش می گذارد. API ها در ArtManagerLocal تعریف شده اند. برای موارد استفاده، Javadoc را در art/libartservice/service/java/com/android/server/art/ArtManagerLocal.java ببینید ( منبع Android 14 ، منبع توسعه منتشر نشده ).

ArtManagerLocal یک تکی است که توسط LocalManagerRegistry نگهداری می شود. یک تابع کمکی com.android.server.pm.DexOptHelper#getArtManagerLocal به شما کمک می کند آن را بدست آورید.

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

بیشتر APIها به نمونه‌ای از PackageManagerLocal.FilteredSnapshot نیاز دارند که اطلاعات همه برنامه‌ها را در خود نگه می‌دارد. می‌توانید آن را با تماس با PackageManagerLocal#withFilteredSnapshot دریافت کنید، جایی که PackageManagerLocal نیز تک‌تنه‌ای است که توسط LocalManagerRegistry نگهداری می‌شود و می‌توانید آن را از com.android.server.pm.PackageManagerServiceUtils#getPackageManagerLocal دریافت کنید.

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

موارد زیر برخی از موارد استفاده معمولی از APIها هستند.

dexopt را برای یک برنامه فعال کنید

می‌توانید در هر زمانی با تماس با ArtManagerLocal#dexoptPackage dexopt را برای هر برنامه فعال کنید.

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());
}

دکسوپت را لغو کنید

اگر عملیاتی با یک تماس 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();

همچنین می‌توانید dexopt پس‌زمینه را که توسط ART Service آغاز شده است، لغو کنید.

getArtManagerLocal().cancelBackgroundDexoptJob();

نتایج dexopt را دریافت کنید

اگر عملیاتی با فراخوانی dexoptPackage آغاز شود، می‌توانید نتیجه را از مقدار بازگشتی دریافت کنید.

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

// Process the result here.
...

سرویس ART همچنین در بسیاری از سناریوها، مانند پس‌زمینه، عملیات dexopt را آغاز می‌کند. برای گوش دادن به همه نتایج dexopt، خواه این عملیات با یک تماس dexoptPackage یا با سرویس ART آغاز شود، از ArtManagerLocal#addDexoptDoneCallback استفاده کنید.

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

اولین آرگومان تعیین می‌کند که آیا فقط به‌روزرسانی‌ها در نتیجه گنجانده شود یا خیر. اگر می خواهید فقط به بسته هایی گوش دهید که توسط dexopt به روز می شوند، آن را روی true تنظیم کنید.

آرگومان دوم مجری callback است. برای اجرای callback در همان رشته ای که dexopt را انجام می دهد، از Runnable::run استفاده کنید. اگر نمی‌خواهید پاسخ به تماس، دکسوپت را مسدود کند، از یک اجراکننده ناهمزمان استفاده کنید.

می توانید چندین تماس را اضافه کنید و ART Service همه آنها را به صورت متوالی اجرا می کند. همه تماس‌های برگشتی برای همه تماس‌های آینده فعال می‌مانند مگر اینکه آنها را حذف کنید.

اگر می‌خواهید پاسخ تماسی را حذف کنید، هنگام افزودن آن، مرجع آن را نگه دارید و از 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 را به طور موقت غیرفعال کنید

هر عملیات dexopt که توسط ART Service آغاز می شود 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 Service آغاز نشده است. در عوض، توسط مدیر بسته از طریق یک تماس dexoptPackage آغاز می شود. بنابراین، BatchDexoptStartCallback راه‌اندازی نمی‌کند . برای غیرفعال کردن dexopt در نصب برنامه، از تماس مدیر بسته با dexoptPackage جلوگیری کنید.

لغو فیلتر کامپایلر برای بسته‌های خاص (Android 15+)

می‌توانید فیلتر کامپایلر را برای بسته‌های خاصی با ثبت یک تماس از طریق setAdjustCompilerFilterCallback لغو کنید. زمانی که بسته‌ای قرار است حذف شود، تماس برگشتی فراخوانی می‌شود، مهم نیست که دکسوپت توسط سرویس ART در هنگام بوت و پس‌زمینه دکسوپت یا با تماس API dexoptPackage آغاز شود.

اگر بسته ای نیاز به تنظیم نداشته باشد، پاسخ تماس باید originalCompilerFilter را برگرداند.

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

شما می توانید تنها یک AdjustCompilerFilterCallback را تنظیم کنید. اگر می خواهید از AdjustCompilerFilterCallback برای لغو فیلتر کامپایلر برای چندین بسته استفاده کنید، باید کد را در یک پاسخ به تماس ترکیب کنید. پاسخ تماس برای همه تماس‌های آینده فعال باقی می‌ماند مگر اینکه آن را پاک کنید.

اگر می‌خواهید پاسخ تماس را پاک کنید، از ArtManagerLocal#clearAdjustCompilerFilterCallback استفاده کنید.

getArtManagerLocal().clearAdjustCompilerFilterCallback();

سایر سفارشی سازی ها

سرویس ART از برخی سفارشی سازی های دیگر نیز پشتیبانی می کند.

آستانه حرارتی را برای دکسوپت پس زمینه تنظیم کنید

کنترل حرارتی کار دکسوپت پس زمینه توسط Job Scheduler انجام می شود. هنگامی که دما به THERMAL_STATUS_MODERATE رسید، کار بلافاصله لغو می شود. آستانه THERMAL_STATUS_MODERATE قابل تنظیم است.

تعیین کنید که dexopt پس زمینه در حال اجرا است یا خیر

کار پس زمینه dexopt توسط Job Scheduler مدیریت می شود و شناسه شغلی آن 27873780 است. برای تعیین اینکه آیا کار در حال اجرا است، از Job Scheduler APIs استفاده کنید.

// 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 باید نام فایل APK با پسوند جایگزین شده با .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 احتمالاً می‌تواند از آن استفاده کند. خط دوم 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 Service شامل موارد زیر است:

  • نمایه نام فایل اشتباهی دارد یا در کنار APK نیست.
  • نمایه در قالب اشتباه است.
  • نمایه با APK مطابقت ندارد. (جمع‌های چک در نمایه با جمع‌های چک فایل‌های .dex در APK مطابقت ندارد.)