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

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

اعتبارًا من Android 14، تتولّى "خدمة 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 (القيمة التلقائية: speed)

هذا هو فلتر المحول البرمجي الاحتياطي للتطبيقات التي تستخدمها تطبيقات أخرى.

من حيث المبدأ، تنفّذ خدمة ART عملية تجميع موجّهة حسب الملف الشخصي (speed-profile) لجميع التطبيقات عندما يكون ذلك ممكنًا، وعادةً ما يتم ذلك أثناء عملية dexopt في الخلفية. ومع ذلك، هناك بعض التطبيقات التي تستخدمها تطبيقات أخرى (إما من خلال <uses-library> أو يتم تحميلها ديناميكيًا باستخدام Context#createPackageContext مع CONTEXT_INCLUDE_CODE). ولا يمكن لهذه التطبيقات استخدام الملفات الشخصية المحلية لأسباب تتعلّق بالخصوصية.

بالنسبة إلى هذا النوع من التطبيقات، إذا تم طلب تجميع موجّه بالملف الشخصي، تحاول &quot;خدمة ART&quot; أولاً استخدام ملف شخصي على السحابة الإلكترونية. إذا لم يكن هناك ملف شخصي على السحابة الإلكترونية، سيعود ART Service إلى استخدام فلتر المحول البرمجي المحدّد بواسطة 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 إلا على تحسين تطبيقات dex التي تم استخدامها خلال آخر عدد محدّد من الأيام.

بالإضافة إلى ذلك، إذا كانت مساحة التخزين منخفضة تقريبًا، سيخفض تطبيق ART Service أثناء عملية dexopt في الخلفية مستوى فلتر المحول البرمجي للتطبيقات التي لم يتم استخدامها خلال آخر عدد محدد من الأيام، وذلك لإخلاء بعض المساحة. سبب المترجم البرمجي لذلك هو 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 (default: false)

هذا مخصّص للاختبار فقط. ويمنع ذلك خدمة ART من جدولة مهمة dexopt التي تعمل في الخلفية.

إذا كانت مهمة dexopt في الخلفية مجدولة ولكن لم يتم تنفيذها بعد، لن يكون لهذا الخيار أي تأثير. وهذا يعني أنّ المهمة ستظل قيد التشغيل.

في ما يلي تسلسل الأوامر المقترَح لمنع تشغيل مهمة dexopt في الخلفية:

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

يمنع السطر الأول جدولة مهمة dexopt في الخلفية، إذا لم تتم جدولتها بعد. يؤدي السطر الثاني إلى إلغاء جدولة مهمة dexopt التي تعمل في الخلفية، إذا كانت مجدولة من قبل، وإلغاء مهمة dexopt التي تعمل في الخلفية على الفور، إذا كانت قيد التشغيل.

واجهات برمجة تطبيقات خدمة ART

تعرض خدمة 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());
}

Cancel 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 فقط، اضبط القيمة على "صحيح".

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

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

يمكنك تجاهل فلتر المحول البرمجي لحِزم معيّنة من خلال تسجيل دالة رد اتصال من خلال setAdjustCompilerFilterCallback. يتم استدعاء دالة الرجوع عندما تتم عملية dexopt لأي حزمة، بغض النظر عمّا إذا كانت عملية dexopt قد بدأت من خلال خدمة ART أثناء عملية التشغيل وعملية dexopt في الخلفية أو من خلال طلب بيانات من واجهة برمجة التطبيقات 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 في الخلفية

تتولّى أداة "جدولة الوظائف" التحكّم في درجة الحرارة لوظيفة dexopt التي تعمل في الخلفية. يتم إلغاء المهمة فورًا عندما تصل درجة الحرارة إلى THERMAL_STATUS_MODERATE. يمكن ضبط الحدّ الأدنى لـ THERMAL_STATUS_MODERATE.

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

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

// 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 هو الملف الشخصي الوحيد الذي يمكن أن تستخدمه &quot;خدمة ART&quot;. يشغّل السطر الثاني 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).