לפני שמתחילים, מומלץ לעיין בסקירה כללית ומקיפה של שירות ART.
החל מ-Android 14, אוסף AOT במכשיר של אפליקציות (שנקראות גם dexopt) מטופלות על ידי ART Service. ART Service הוא חלק מ-ART ולהתאים אותו אישית באמצעות מאפייני המערכת וממשקי API.
מאפייני המערכת
שירות ART תומך בכל אפשרויות dex2oat.
בנוסף, ART Service תומך במאפייני המערכת הבאים:
pm.dexopt.<reason>
זוהי קבוצה של מאפייני מערכת שקובעים את מסנני ברירת המחדל של המהדר (compiler) מכל סיבות ההידור המוגדרות מראש שמתוארות בתרחישים של 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 (ברירת מחדל: מהירות)
זהו מסנן המהדר (compiler) החלופי לאפליקציות שמשמשות אפליקציות אחרות.
בעיקרון, שירות 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
ופרופילים של המשימות תמיד קשורים לליבת המעבד (CPU) בשימוש, ללא קשר למספר המקסימלי של שרשורים בו-זמנית (כפי שצוין שלמעלה).
יכול להיות שבהפעלה אחת של dex2oat לא ייעשה שימוש מלא בכל ליבות המעבד (CPU),
מתוך dalvik.vm.*dex2oat-threads
. לכן, כשנגדיל את מספר dex2oat,
הפעלות (pm.dexopt.<reason>.concurrency
) יכולות לנצל בצורה טובה יותר את הליבות של המעבד (CPU),
לזרז את ההתקדמות הכוללת של dexopt. האפשרות הזאת שימושית במיוחד במהלך
לאתחל.
עם זאת, יותר מדי הפעלות dex2oat עלולות לגרום למכשיר להתרוקן
את הזיכרון, למרות שאפשר לצמצם את האפשרות הזו על ידי הגדרה של dalvik.vm.dex2oat-swap
לערך
true
כדי לאפשר שימוש בקובץ החלפה. גם הפעלות רבות מדי עלולות לגרום
החלפת הקשר מיותרת. לכן, צריך לכוונן את המספר הזה
בהתאם למוצר.
pm.dexopt.downgrad_after_inactive_days (ברירת מחדל: לא מוגדר)
אם האפשרות הזו מוגדרת, ART Service מבטל רק את האפליקציות שהשתמשו בהן עד הפעם האחרונה מספר ימים.
בנוסף, אם נפח האחסון כמעט נמוך, במהלך dexopt ברקע, שירות ART
משדרג לאחור את מסנן המהדר של אפליקציות שלא נעשה בהן שימוש עד
מספר ימים כדי לפנות מקום. סיבת המהדר (compiler) באפשרות הזו היא inactive
,
ומסנן המהדר נקבע על ידי pm.dexopt.inactive
. המרחב המשותף
הסף להפעלת התכונה הזו הוא סף נפח האחסון הפנוי במנהל האחסון
(ניתן להגדרה דרך ההגדרות הגלובליות sys_storage_threshold_percentage
ו
sys_storage_threshold_max_bytes
, ברירת המחדל: 500MB) ועוד 500MB.
אם רוצים להתאים אישית את רשימת החבילות באמצעות
ArtManagerLocal#setBatchDexoptStartCallback
, החבילות ברשימה שסיפקת
מאת BatchDexoptStartCallback
עבור bg-dexopt
אף פעם לא משודרגים לאחור.
pm.dexopt.disable_bg_dexopt (ברירת המחדל: false)
האוסף הזה מיועד לבדיקה בלבד. הפעולה מונעת משירות ART לתזמן את הרקע עבודת פירוק.
אם משימת העיבוד ברקע כבר מתוזמנת אבל עדיין לא הופעלה, לאפשרות אין השפעה. כלומר, המשימה עדיין תפעל.
רצף מומלץ של פקודות למניעת משימת dexopt ברקע ריצה:
setprop pm.dexopt.disable_bg_dexopt true
pm bg-dexopt-job --disable
השורה הראשונה מונעת תזמון של משימת dexopt ברקע, אם היא עדיין לא נקבעו תאריכים. בשורה השנייה מבטלים את התזמון של משימת dexopt ברקע, אם הוא כבר מתוזמן, והוא מבטל את עבודת דקספט ברקע באופן מיידי, אם המודעה פועלת.
ממשקי API של שירות ART
שירות ART חושף ממשקי API של Java להתאמה אישית. ממשקי ה-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 לאפליקציה
אפשר להפעיל dexopt לכל אפליקציה בכל שלב באמצעות התקשרות
ArtManagerLocal#dexoptPackage
try (var snapshot = getPackageManagerLocal().withFilteredSnapshot()) {
getArtManagerLocal().dexoptPackage(
snapshot,
"com.google.android.calculator",
new DexoptParams.Builder(ReasonMapping.REASON_INSTALL).build());
}
אתם יכולים גם להעביר את הסיבה שלכם לבדיקה. אם תעשו זאת, סיווג העדיפות יש להגדיר את מסנן המהדר (compiler) באופן מפורש.
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();
אפשר גם לבטל את הסרת הנתונים ברקע ביוזמת שירות ART.
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
. אם לא רוצים
קריאה חוזרת (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
אחד לכל היותר. הקריאה החוזרת (callback)
יישארו פעילים בכל השיחות העתידיות, אלא אם תמחקו את ההגדרה.
כדי למחוק את הקריאה החוזרת, צריך להשתמש
ArtManagerLocal#clearScheduleBackgroundDexoptJobCallback
getArtManagerLocal().clearScheduleBackgroundDexoptJobCallback();
השבתה זמנית של Dexopt
כל פעולת dexopt שמתרחשת על ידי שירות ART מפעילה
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
.
שינוי מסנן המהדר בחבילות מסוימות (Android 15 ואילך)
כדי לשנות את מסנן המהדר (compiler) בחבילות מסוימות, אפשר לבצע רישום של
התקשרות חזרה באמצעות setAdjustCompilerFilterCallback
. הקריאה החוזרת היא
בכל פעם שחבילה עומדת לעבור ניקוי, ללא קשר לתהליך העיבוד
שירות ART במהלך הפעלה והסרה ברקע, או באמצעות קריאה ל-API של dexoptPackage
.
אם לא צריך לבצע התאמה בחבילה, צריך להחזיר את הקריאה החוזרת
originalCompilerFilter
getArtManagerLocal().setAdjustCompilerFilterCallback(
Runnable::run,
(packageName, originalCompilerFilter, reason) -> {
if (isVeryImportantPackage(packageName)) {
return "speed-profile";
}
return originalCompilerFilter;
});
אפשר להגדיר רק AdjustCompilerFilterCallback
אחד. אם רוצים להשתמש
AdjustCompilerFilterCallback
כדי לשנות את מסנן המהדר של מספר מיקומים
חבילות, עליך לשלב את הקוד לקריאה חוזרת אחת. הקריאה החוזרת (callback) נשארה
פעיל לכל השיחות העתידיות, אלא אם תמחקו את ההגדרה.
כדי למחוק את הקריאה החוזרת, צריך להשתמש
ArtManagerLocal#clearAdjustCompilerFilterCallback
getArtManagerLocal().clearAdjustCompilerFilterCallback();
התאמות אישיות אחרות
שירות ART תומך גם בכמה התאמות אישיות אחרות.
הגדרת סף הטמפרטורה של dexopt ברקע
בקרת התרמית של משימת dexopt ברקע מתבצעת על ידי Job Scheduler.
המשימה מתבטלת מיד כשהטמפרטורה תגיע לאפס
THERMAL_STATUS_MODERATE
הסף של
ניתן לכוונן את THERMAL_STATUS_MODERATE
.
איך לבדוק אם פעולת dexopt ברקע פועלת
משימת ה-dexopt ברקע מנוהלת על ידי Job Scheduler, ומזהה המשימה שלה הוא
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
כדי להשתמש בפרופיל להדרכת 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).