תצורת שירות ART

לפני שתתחיל, ראה סקירה כללית ברמה גבוהה של שירות ART .

החל מאנדרואיד 14, הידור AOT במכשיר עבור אפליקציות (הידוע גם בשם dexopt) מטופל על ידי ART Service. שירות ART הוא חלק ממודול ART, ותוכל להתאים אותו באמצעות מאפייני מערכת וממשקי API.

מאפייני מערכת

ART Service תומך בכל האפשרויות הרלוונטיות של 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 ) עבור כל האפליקציות במידת האפשר, בדרך כלל במהלך ניקוי רקע. עם זאת, יש כמה אפליקציות המשמשות אפליקציות אחרות (או דרך <uses-library> או נטענות באופן דינמי באמצעות Context#createPackageContext עם CONTEXT_INCLUDE_CODE ). אפליקציות כאלה אינן יכולות להשתמש בפרופילים מקומיים מסיבות פרטיות.

עבור אפליקציה כזו, אם מתבקש הידור מונחה פרופיל, ART Service מנסה תחילה להשתמש בפרופיל ענן. אם לא קיים פרופיל ענן, שירות 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 ) יכולה לנצל טוב יותר את ליבות ה-CPU, כדי להאיץ את ההתקדמות הכוללת של dexopt. זה שימושי במיוחד במהלך האתחול.

עם זאת, יותר מדי הפעלות ל-dex2oat עלולות לגרום להתקן להיגמר הזיכרון, למרות שניתן להפחית זאת על ידי הגדרת dalvik.vm.dex2oat-swap ל- true כדי לאפשר שימוש בקובץ swap. יותר מדי פניות עלולות גם לגרום להחלפת הקשר מיותרת. לכן, יש לכוון את המספר הזה בקפידה על בסיס מוצר למוצר.

pm.dexopt.downgrade_after_inactive_days (ברירת מחדל: לא מוגדר)

אם אפשרות זו מוגדרת, ART Service מוציא רק אפליקציות ששימשו במהלך מספר הימים האחרון.

בנוסף, אם נפח האחסון כמעט נמוך, במהלך ניקוי רקע, ART Service משדרג לאחור את מסנן המהדר של אפליקציות שלא נעשה בהן שימוש במהלך הימים האחרונים, כדי לפנות מקום. הסיבה המהדרת לכך 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 Service לתזמן את עבודת ה-dexopt ברקע.

אם עבודת dexopt ברקע כבר מתוכננת אך עדיין לא רצה, לאפשרות זו אין השפעה. כלומר, העבודה עדיין תפעל.

רצף פקודות מומלץ למניעת הפעלת משימת ה-dexopt ברקע הוא:

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

השורה הראשונה מונעת את תזמון עבודת ה-dexopt ברקע, אם היא עדיין לא מתוכננת. השורה השנייה מבטלת את התזמון של משימת ניקוי הרקע, אם היא כבר מתוכננת, והיא מבטלת את משימת ניקוי הרקע באופן מיידי, אם היא פועלת.

ממשקי API של שירות ART

ART Service חושף ממשקי API של Java להתאמה אישית. ממשקי ה-API מוגדרים ב- ArtManagerLocal . עיין ב-Javadoc ב- art/libartservice/service/java/com/android/server/art/ArtManagerLocal.java עבור שימושים ( מקור אנדרואיד 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());
}

אתה יכול גם להעביר את הסיבה ל-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 Service.

getArtManagerLocal().cancelBackgroundDexoptJob();

קבל תוצאות Dexopt

אם פעולה יזומה על ידי קריאת dexoptPackage , תוכל לקבל את התוצאה מערך ההחזרה.

DexoptResult result;
try (var snapshot = getPackageManagerLocal().withFilteredSnapshot()) {
  result = getArtManagerLocal().dexoptPackage(...);
}

// Process the result here.
...

ART Service גם יוזם פעולות dexopt בעצמו בתרחישים רבים, כגון רקע dexopt. כדי להאזין לכל תוצאות ה-dexopt, בין אם הפעולה יזומה באמצעות שיחת dexoptPackage או על-ידי ART Service, השתמש ב- ArtManagerLocal#addDexoptDoneCallback .

getArtManagerLocal().addDexoptDoneCallback(
    false /* onlyIncludeUpdates */,
    Runnable::run,
    (result) -> {
      // Process the result here.
      ...
    });

הארגומנט הראשון קובע אם לכלול רק עדכונים בתוצאה. אם אתה רוצה להאזין רק לחבילות שמתעדכנות על ידי dexopt, הגדר אותו כ-true.

הטיעון השני הוא המבצע של ה-callback. כדי לבצע את ההתקשרות חזרה באותו שרשור שמבצע dexopt, השתמש ב- Runnable::run . אם אינך רוצה שהקריאה לאחור תחסום את dexopt, השתמש ב-executor אסינכרוני.

אתה יכול להוסיף מספר התקשרויות חוזרות, ו-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 Service יוזם את פעולות ה-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 ברקע

כברירת מחדל, עבודת ניקוי הרקע פועלת פעם ביום כשהמכשיר לא פעיל ונטען. ניתן לשנות זאת באמצעות 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 (AOSP ניסיוני)+)

אתה יכול לעקוף את מסנן המהדר עבור חבילות מסוימות על ידי רישום התקשרות חוזרת דרך setAdjustCompilerFilterCallback . ההתקשרות חוזרת נקראת בכל פעם שחבילה עומדת לעבור dexopt, לא משנה שה-dexopt יוזם על ידי ART Service במהלך אתחול ו-dexopt ברקע או על ידי קריאת dexoptPackage API.

אם חבילה אינה זקוקה להתאמה, ההתקשרות חזרה חייבת להחזיר את 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 ברקע מתבצעת על ידי Job Scheduler. העבודה מבוטלת מיד כשהטמפרטורה מגיעה THERMAL_STATUS_MODERATE . ניתן לכוונן את הסף של THERMAL_STATUS_MODERATE .

קבע אם Dexopt ברקע פועל

עבודת dexopt ברקע מנוהלת על ידי Job Scheduler, ומזהה המשרה שלה הוא 27873780 . כדי לקבוע אם העבודה פועלת, השתמש בממשקי 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 Service יכול להשתמש בו. השורה השנייה מפעילה 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).