قبل از شروع، یک نمای کلی سطح بالا از سرویس 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 مطابقت ندارد.)