قبل البدء، يمكنك الاطّلاع على نظرة عامة عالية المستوى حول خدمة ART.
بدءًا من Android 14، تتولى خدمة ART عملية تجميع التطبيقات (المعروفة أيضًا باسم dexopt) باستخدام تقنية AOT على الجهاز. خدمة 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.downgrade_after_inactive_days (الإعداد التلقائي: غير محدّد)
في حال ضبط هذا الخيار، لن تلغي خدمة ART ميزة Dexopt إلا للتطبيقات المستخدَمة خلال آخر عدد محدّد من الأيام.
بالإضافة إلى ذلك، إذا كانت مساحة التخزين منخفضة تقريبًا، أثناء تحسين 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());
}
إلغاء 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.
الوسيطة الثانية هي عنصر تنفيذ طلب إعادة الاتصال. لتنفيذ دالة الاستدعاء في 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 في الخلفية
يتم تشغيل مهمة 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
. لإيقاف dexopt عند تثبيت التطبيق، عليك منع
مدير الحِزم من الاتصالdexoptPackage
.
إلغاء فلتر المُجمِّع لحِزم معيّنة (الإصدار 15 من Android والإصدارات الأحدث)
يمكنك إلغاء فلتر المُجمِّع لحِزم معيّنة من خلال تسجيل callback
من خلال setAdjustCompilerFilterCallback
. يتمّ استدعاء الدالة المُعاد الاتصال بها
عند بدء عملية إزالة ترميز حزمة، بغض النظر عمّا إذا كانت عملية إزالة الترميز قد بدأت من قِبل
خدمة ART أثناء عملية التمهيد وعملية إزالة الترميز في الخلفية أو من خلال طلب بيانات من واجهة برمجة التطبيقات 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 في الخلفية من خلال أداة جدولة المهام، ومعرّف المهمة هو
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
لاستخدام ملف تعريف لتوجيه أداة 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).