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

قبل البدء، يمكنك إلقاء نظرة عامة وشاملة على خدمة ART.

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

خصائص النظام

تدعم خدمة ART جميع خيارات dex2oat

بالإضافة إلى ذلك، تتوافق خدمة ART مع خصائص النظام التالية:

pm.dexopt.<reason>

هذا عبارة عن مجموعة من خصائص النظام التي تحدد عوامل تصفية التجميع التلقائي لكل أسباب التجميع المحددة مسبقًا والموضحة في سيناريوهات إيقاف عرض المحتوى.

لمزيد من المعلومات، يُرجى الاطّلاع على فلاتر المُجمِّع.

القيم التلقائية العادية هي:

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

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

‫pm.dexopt.downgrade_after_inactive_days (الإعداد التلقائي: غير محدّد)

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

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

يشير هذا المصطلح إلى تسلسل مقترَح من الأوامر لمنع مهمة تحسين الخلفية من الجري هو:

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

يمكنك أيضًا اختيار سبب إثبات الملكية الخاص بك. إذا قمت بذلك، فسيتم تحديد فئة الأولوية يجب تعيين عامل تصفية التجميع بشكل صريح.

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

يمكنك أيضًا إلغاء 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.

الوسيطة الثانية هي عنصر تنفيذ طلب إعادة الاتصال. لتنفيذ معاودة الاتصال على سلسلة المحادثات نفسها التي تنفّذ 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 مؤقتًا

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

إذا كانت العملية التي تلغيها هي تحسين 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 Service عملية dexopt التي يتم إجراؤها عند تثبيت التطبيق. بدلاً من ذلك، يبدأ مدير الحِزم عملية التثبيت من خلال مكالمة dexoptPackage. لذلك، لا يؤدي إلى تشغيل BatchDexoptStartCallback ولإيقافها عند تثبيت التطبيق، عليك منع مدير الحزمة من الاتصال بـ 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 أيضًا بعض التخصيصات الأخرى.

ضبط الحدّ الأدنى لدرجة الحرارة في الخلفية

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

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

تتم إدارة مهمة dexopt في الخلفية من خلال أداة جدولة المهام، ومعرّف المهمة هو 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، ضَع ملف .prof أو ملف .dm بجانب ملف APK.

يجب أن يكون ملف .prof ملفًا شخصيًا بتنسيق ثنائي، كما يجب أن يكون اسم الملف اسم ملف APK + .prof. على سبيل المثال:

base.apk.prof

يجب أن يكون اسم ملف .dm هو اسم ملف APK مع استبدال امتداد .dm بملف APK. على سبيل المثال:

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.)