إعدادات خدمة ART

قبل البدء، يمكنك الاطّلاع على نظرة عامة عالية المستوى حول خدمة ART.

بدءًا من الإصدار 14 من نظام التشغيل Android، تعالج "خدمة ART" تجميع AOT على الجهاز للتطبيقات (المعروفة أيضًا باسم dexopt). وتعد خدمة ART جزءًا من وحدة ART، ويمكنك تخصيصها من خلال خصائص النظام وواجهات برمجة التطبيقات.

خصائص النظام

تتوافق خدمة 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) لجميع التطبيقات كلما أمكن ذلك، وعادةً ما يكون ذلك أثناء عملية 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 وملفّات تعريف المهام مرتبطة دائمًا باستخدام ملفّات تعريف وحدة المعالجة المركزية، بغض النظر عن الحد الأقصى لعدد سلاسل المهام المتزامنة (الموضّحة أعلاه).

قد لا يؤدي استدعاء dex2oat واحد إلى استخدام جميع نوى وحدة المعالجة المركزية بالكامل، بغض النظر عن dalvik.vm.*dex2oat-threads. وبالتالي، يمكن أن تؤدي زيادة عدد عمليات التفعيل الخاصة بـ dex2oat (pm.dexopt.<reason>.concurrency) إلى استخدام نوى وحدة المعالجة المركزية بشكل أفضل، وبالتالي تسريع التقدّم العام لعملية dexopt. وهذا مفيد بشكل خاص أثناء التشغيل.

ومع ذلك، قد يؤدي إجراء عدد كبير جدًا من عمليات استدعاء dex2oat إلى نفاد الذاكرة في الجهاز، على الرغم من أنّه يمكن تخفيف ذلك من خلال ضبط dalvik.vm.dex2oat-swap على true للسماح باستخدام ملف تبديل. وقد يؤدي أيضًا استخدام عدد كبير جدًا من عمليات الاستدعاء إلى تبديل السياق غير الضروري. لذلك، يجب ضبط هذا الرقم بعناية على أساس كل منتج على حدة.

pm.dexopt.down للمساعدة_after_inactive_days (الإعداد التلقائي: لم يتم الضبط)

في حال ضبط هذا الخيار، لن تتوقف خدمة ART عن ترجمة التطبيقات إلا في حال استخدامها خلال عدد معيّن من الأيام.

بالإضافة إلى ذلك، إذا كانت مساحة التخزين منخفضة تقريبًا، أثناء تحسين dexopt في الخلفية، تُنزِّل خدمة ART فلتر المُجمِّع للتطبيقات التي لم يتم استخدامها خلال العدد المحدَّد في آخر أيام، لإخلاء بعض المساحة. سبب المُجمِّع لذلك هو inactive، ويتم تحديد فلتر المُجمِّع من خلال pm.dexopt.inactive. الحدّ الأدنى لمساحة التخزين الذي يؤدي إلى تفعيل هذه الميزة هو الحدّ الأدنى لمساحة التخزين في "أداة إدارة مساحة التخزين" (يمكن ضبطه من خلال الإعدادات العامة sys_storage_threshold_percentage و sys_storage_threshold_max_bytes، الإعداد التلقائي: 500 ميغابايت) بالإضافة إلى 500 ميغابايت.

في حال تخصيص قائمة الحِزم من خلال ArtManagerLocal#setBatchDexoptStartCallback، لن يتم أبدًا الرجوع إلى إصدارات سابقة من الحِزم المدرَجة في القائمة التي يوفّرها BatchDexoptStartCallback لتطبيق bg-dexopt.

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 Service

تعرض خدمة ART واجهات برمجة تطبيقات Java للتخصيص. يتم تحديد واجهات برمجة التطبيقات في 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;

تتطلّب معظم واجهات برمجة التطبيقات نسخة افتراضية من PackageManagerLocal.FilteredSnapshot، تحتفظ بمعلومات جميع التطبيقات. يمكنك الحصول عليه من خلال استدعاء PackageManagerLocal#withFilteredSnapshot، حيث يكون PackageManagerLocal هو أيضًا عنصر فريد يملكها LocalManagerRegistry ويمكن الحصول عليه من com.android.server.pm.PackageManagerServiceUtils#getPackageManagerLocal.

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

في ما يلي بعض حالات الاستخدام الشائعة لواجهات برمجة التطبيقات.

بدء عملية dexopt لتطبيق

يمكنك تفعيل أداة 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());
}

إلغاء الاشتراك

إذا تم بدء عملية من خلال طلب 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.

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.

الوسيطة الثانية هي المسؤول عن تنفيذ طلب إعادة الاتصال. لتنفيذ دالة الاستدعاء في Runnable::run، استخدِم Runnable::run. إذا كنت لا تريد أن تحظر دالّة callback عملية 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 في الخلفية تلقائيًا مرة واحدة في اليوم عندما يكون الجهاز في وضع السكون ويُستخدَم كشاحن. ويمكن تغيير ذلك باستخدام ArtManagerLocal#setScheduleBackgroundDexoptJobCallback.

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

يمكنك ضبط ScheduleBackgroundDexoptJobCallback واحد كحد أقصى. سيظل خيار معاودة الاتصال فعالًا لجميع المكالمات المستقبلية ما لم تُلغِه.

إذا كنت تريد محو معاودة الاتصال، استخدِم ArtManagerLocal#clearScheduleBackgroundDexoptJobCallback.

getArtManagerLocal().clearScheduleBackgroundDexoptJobCallback();

إيقاف أداة dexopt مؤقتًا

تؤدي أي عملية dexopt تبدأها خدمة ART إلى بدء BatchDexoptStartCallback. يمكنك مواصلة إلغاء العمليات لإيقاف الرصد بشكل فعال.

إذا كانت العملية التي تلغيها هي تحسين dex في الخلفية، ستتّبع سياسة إعادة المحاولة التلقائية (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();

لا تبدأ "خدمة ART" عملية الدمج التي يتم إجراؤها عند تثبيت التطبيق. بدلاً من ذلك، يبدأ مدير الحزمة من خلال استدعاء dexoptPackage. وبالتالي، لا يؤدي ذلك إلى بدء BatchDexoptStartCallback. لإيقاف dexopt عند تثبيت التطبيق، عليك منع مدير الحِزم من الاتصالdexoptPackage.

إلغاء فلتر المُجمِّع لحِزم معيّنة (الإصدار 15 من Android والإصدارات الأحدث)

يمكنك إلغاء فلتر برنامج التجميع لحِزم معيّنة من خلال تسجيل طلب معاودة الاتصال من خلال setAdjustCompilerFilterCallback. يتمّ استدعاء الدالة المرجعية عند بدء تحويل حزمة إلى رمز DEX، بغض النظر عمّا إذا كان بدء عملية التحويل قد تمّ من قِبل خدمة ART أثناء عملية التمهيد وتحويل الحزمة إلى رمز DEX في الخلفية أو من خلال طلب بيانات من واجهة برمجة التطبيقات dexoptPackage.

إذا كانت الحزمة لا تحتاج إلى تعديل، يجب أن تعرض معاودة الاتصال originalCompilerFilter.

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

يمكنك ضبط سمة AdjustCompilerFilterCallback واحدة فقط. إذا كنت تريد استخدام AdjustCompilerFilterCallback لإلغاء فلتر المُجمِّع لعدة حِزم، عليك دمج الرمز في ردّ اتصال واحد. تظل ميزة معاودة الاتصال مفعَّلة لجميع المكالمات المستقبلية ما لم تلغِها.

إذا كنت تريد محو معاودة الاتصال، استخدِم ArtManagerLocal#clearAdjustCompilerFilterCallback.

getArtManagerLocal().clearAdjustCompilerFilterCallback();

عمليات تخصيص أخرى

توفّر خدمة ART أيضًا بعض التخصيصات الأخرى.

ضبط الحدّ الأقصى للحرارة لميزة dexopt في الخلفية

تتولى أداة جدولة المهام تنفيذ التحكُّم الحراري في مهمة ضبط الخلفية. يتم إلغاء المهمة على الفور عند بلوغ درجة الحرارة THERMAL_STATUS_MODERATE. يمكن ضبط حدّ القيمة THERMAL_STATUS_MODERATE.

تحديد ما إذا كان أداة dexopt قيد التشغيل في الخلفية

تتم إدارة مهمة dexopt في الخلفية من خلال أداة جدولة المهام، ومعرّف المهمة هو 27873780. لتحديد ما إذا كان المهام قيد التشغيل، استخدِم واجهات برمجة تطبيقات Job Scheduler.

// 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، ضَع ملف .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 للملف الشخصي ما يلي:

  • يحتوي الملف الشخصي على اسم ملف غير صحيح أو ليس بجانب حزمة APK.
  • التنسيق غير صحيح في الملف الشخصي.
  • لا يتطابق الملف الشخصي مع ملف APK. (لا تطابق المجاميع الاختبارية في الملف الشخصي المجاميع الاختبارية لملفات .dex في حزمة APK.)