מעקב אחר השימוש בזיכרון ה-Flash

Watchdog עוקב אחרי השימוש בזיכרון הפלאש על ידי מעקב אחרי כמות הכתיבה הכוללת של קלט/פלט בדיסק שבוצעה על ידי כל האפליקציות והשירותים, באמצעות נתוני הסטטיסטיקה של קלט/פלט בדיסק לכל מזהה משתמש (UID) שחשופים על ידי הליבה במיקום ‎/proc/uid_io/stats. כשאפליקציה או שירות חורגים מהסף של שימוש יתר בקלט/פלט בדיסק, Watchdog מבצע פעולות באפליקציה או בשירות. ערכי הסף לשימוש יתר בקלט/פלט בדיסק והפעולה שצריך לבצע במקרה של שימוש יתר מוגדרים מראש בהגדרות של שימוש יתר בקלט/פלט בדיסק.

ערכי סף לשימוש יתר

  • ערכי הסף לשימוש יתר ב-I/O בדיסק נאכפים על בסיס יומי. כלומר, כל פעולות הכתיבה שבוצעו על ידי אפליקציה או שירות נצברות מתחילת היום הקלנדרי הנוכחי לפי שעון UTC, ונבדקות מול ערכי הסף שהוגדרו בהגדרות של שימוש יתר.
  • כשהרכב מופעל כמה פעמים ביום נתון, מודול Watchdog מאחסן את נתוני הסטטיסטיקה של השימוש ב-I/O בדיסק בזיכרון הפלאש ומאגד אותם מאז תחילת היום הקלנדרי הנוכחי לפי שעון UTC.

פעולות של שימוש יתר

כשאפליקציה חורגת שוב ושוב מהספים שהוגדרו לשימוש יתר ב-I/O בדיסק, Watchdog מבצע את הפעולות שהוגדרו בהגדרות של שימוש יתר.

  • כל האפליקציות והשירותים של הספקים נחשבים חיוניים ליציבות המערכת הכוללת, ולכן הם לא יופסקו בגלל שימוש מוגזם ב-I/O בדיסק. עם זאת, אפשר להגדיר רשימה של אפליקציות ושירותים של ספקים שאפשר לסגור בבטחה במסגרת ההגדרה של שימוש יתר.
  • אפשר לסגור בבטחה את כל האפליקציות של הצד השלישי.

כשאפשר לסיים את האפליקציה או השירות בבטחה, Watchdog משבית אותם עם מצב הרכיב PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED .

הגדרה של שימוש יתר

הגדרת השימוש יתר מכילה את ערכי הסף והפעולות של שימוש יתר ב-I/O בדיסק. הגדרות ברירת המחדל של שימוש יתר מוגדרות בתמונות המערכת ובתמונות של הספק, ונשלחות עם ה-build. ספקים יכולים לכלול את הגדרות הספק בתמונת הספק. אם לא מציינים הגדרות של הספק, המערכת משתמשת בהגדרות שלה גם באפליקציות ובשירותים של הספק.

Watchdog חושף ממשקי API של מערכת דרך CarWatchdogManager, שמאפשרים לאפליקציות או לשירותים של ספקים לעדכן את הגדרות הספק בכל שלב.

הגדרת תצורה של שימוש יתר

ההגדרות של שימוש יתר מחולקות לפי סוג הרכיב, למשל מערכת, ספק וצד שלישי. יצרני ציוד מקורי צריכים לעדכן רק את ההגדרות של רכיבי הספק.

הגדרות אישיות של ספק

בהגדרות של הספק מוגדרים הסף והפעולות לשימוש יתר ב-I/O בדיסק לכל האפליקציות והשירותים של הספק, וכל המפות ואפליקציות המדיה. ההגדרה מכילה את שדות ההגדרה הבאים.

  • תחיליות של חבילות של ספקים. כל החבילות שמותקנות במחיצה של הספק נחשבות לחבילות של הספק. בנוסף לחבילות האלה, ספקים יכולים לסווג חבילות מותקנות מראש כחבילות של ספקים על ידי הוספת הקידומות של החבילות להגדרה vendor package prefixes. ההגדרה הזו לא מקבלת ביטויים רגולריים.
  • חבילות שאפשר לסגור. ספקים יכולים לציין אילו חבילות שלהם בטוחות לסגירה על ידי הוספת שמות החבילות המלאים להגדרה safe-to-terminate packages.
  • מיפויים של קטגוריות אפליקציות. ספקים יכולים למפות כל חבילת אפליקציות (כולל חבילות של צד שלישי) לאחת משתי הקטגוריות הנתמכות של אפליקציות – אפליקציות מפה ואפליקציות מדיה. המיפוי הזה נעשה כדי לספק לאפליקציות מפות ולאפליקציות מדיה ערכי סף גבוהים יותר של שימוש יתר ב-I/O בדיסק, כי האפליקציות האלה נוטות להוריד ולכתוב יותר נתונים בדיסק בהשוואה לסוגי אפליקציות אחרים.
  • סכומי סף ברמת הרכיב. הגדרת ערכי סף כלליים לכל החבילות של הספק (כלומר, החבילות שלא חלות עליהן ערכי סף ספציפיים לחבילות או ערכי סף ספציפיים לקטגוריות של אפליקציות). ספקים חייבים להגדיר ערכי סף שאינם אפס ברמת הרכיב כשהם מגדירים את ההגדרות של שימוש יתר ב-I/O בדיסק.
  • סכומי סף ספציפיים לחבילות. ספקים יכולים להגדיר ערכי סף מיוחדים לחבילות ספציפיות של ספקים. המיפויים צריכים לכלול את שמות החבילות המלאים. הסף שמוגדר בתצורה הזו מקבל עדיפות על פני הסף שמוגדר בתצורות אחרות לחבילה מסוימת.
  • סף ספציפי לקטגוריית אפליקציה. ספקים יכולים לציין ערכי סף מיוחדים לקטגוריות ספציפיות של אפליקציות. קטגוריות האפליקציות חייבות להיות אחת מהקטגוריות הנתמכות – אפליקציות מפות ואפליקציות מדיה. הסף שמוגדר בהגדרה הזו ממופה לחבילות ספציפיות באמצעות מיפויים של קטגוריות אפליקציות.
  • ערכי סף ברמת המערכת. אסור לספקים לציין את ההגדרה הזו.

אפשר לעדכן את ההגדרות של תחילית החבילה של הספק, חבילות שניתן לסגור בבטחה, סף ברמת הרכיב וסף ספציפי לחבילה רק באמצעות הגדרות הספק לאפליקציות ולשירותים של הספק. אפשר לעדכן את ההגדרה של סף ספציפי לקטגוריית אפליקציה רק באמצעות הגדרת הספק לכל האפליקציות של מפות ומדיה.

ערכי הסף לשימוש יתר מכילים את כמות הבייטים שמותר לכתוב במהלך:

  • מצב חזית לעומת מצב רקע של אפליקציה או שירות
  • מצב 'חניה' של המערכת

הסיווג הזה מאפשר לאפליקציות ולשירותים בחזית המשתמש לכתוב יותר נתונים מאשר לאפליקציות ולשירותים ברקע. במצב Garage, האפליקציות והשירותים נוטים להוריד עדכונים, ולכן לכל אחד מהם נדרש סף גבוה יותר מאשר לאפליקציות ולשירותים שפועלים במצבים אחרים.

הגדרות מערכת והגדרות של צד שלישי

יצרני ציוד מקורי לא צריכים לעדכן את ההגדרות של המערכת ושל צד שלישי.

  • הגדרות המערכת מגדירות את פעולות הסף ואת הפעולות במקרה של שימוש יתר ב-I/O לאפליקציות ולשירותים של המערכת.
    • ההגדרה הזו יכולה גם לעדכן את המיפויים של קטגוריות האפליקציות. לכן, שדה התצורה הזה משותף בין הגדרות המערכת לבין הגדרות הספק.
  • ההגדרות של צד שלישי מגדירות ערכי סף לכל האפליקציות של צד שלישי. כל האפליקציות שלא מותקנות מראש במערכת הן אפליקציות של צד שלישי.
    • כל האפליקציות של צד שלישי מקבלות את אותם ערכי סף (לדוגמה, אף אפליקציה של צד שלישי לא מקבלת ערכי סף מיוחדים), מלבד אפליקציות מפות ואפליקציות מדיה, שהערכי הסף שלהן מוגדרים בהגדרות של הספק.
    • ערכי הסף הבאים לשימוש יתר ב-I/O בדיסק הם ערכי ברירת המחדל לאפליקציות של צד שלישי. ערכי הסף האלה נשלחים עם קובץ האימג' של המערכת.
      • כתיבה של 3 GiB במצב 'חזית' של האפליקציה.
      • כתיבה בנפח 2 GiB במצב הרקע של האפליקציה.
      • כתיבה בנפח 4 GiB במצב 'מחסן המערכת'.
    • אלה ערכי הסף הבסיסיים. הסף הזה מתעדכן ככל שמתקבל מידע נוסף על השימוש ב-I/O בדיסק.

פורמט XML של הגדרות שימוש יתר

אפשר להציב את הגדרות ברירת המחדל של הספק (אופציונלי) במיקום /vendor/etc/automotive/watchdog/resource_overuse_configuration.xml בקובץ האימג' של ה-build. אם לא מציינים את ההגדרה הזו, ההגדרה שמוגדרת במערכת חלה גם על אפליקציות ושירותים של ספקים.

קובץ ה-XML צריך להכיל רק תג אחד לכל שדה תצורה. צריך להגדיר את ההגדרות של שימוש יתר ב-I/O בקובץ ה-XML. כל ערכי הסף צריכים להיות מצוינים ביחידת MiB.

בהמשך מופיעה דוגמה להגדרת XML:

<resourceOveruseConfiguration version="1.0">
      <componentType> VENDOR </componentType>

      <!-- List of safe to kill vendor packages. -->
      <safeToKillPackages>
            <package> com.vendor.package.A </package>
            <package> com.vendor.package.B </package>
      </safeToKillPackages>

      <!-- List of vendor package prefixes. -->
      <vendorPackagePrefixes>
            <packagePrefix> com.vendor.package </packagePrefix>
      </vendorPackagePrefixes>

      <!-- List of unique package names to app category mappings. -->
      <packagesToAppCategoryTypes>
            <packageAppCategory type="MEDIA"> com.vendor.package.A </packageAppCategory>
            <packageAppCategory type="MAPS"> com.google.package.B </packageAppCategory>
            <packageAppCategory type="MEDIA"> com.third.party.package.C </packageAppCategory>
      </packagesToAppCategoryTypes>

      <ioOveruseConfiguration>
        <!-- Thresholds in MiB for all vendor packages that don't have package specific thresholds. -->
            <componentLevelThresholds>
                  <state id="foreground_mode"> 1024 </state>
                  <state id="background_mode"> 512 </state>
                  <state id="garage_mode"> 3072 </state>
            </componentLevelThresholds>

            <packageSpecificThresholds>
                  <!-- IDs must be unique -->
                  <perStateThreshold id="com.vendor.package.C">
                    <state id="foreground_mode"> 400 </state>
                    <state id="background_mode"> 100 </state>
                    <state id="garage_mode"> 200 </state>
                  </perStateThreshold>

                  <perStateThreshold id="com.vendor.package.D">
                    <state id="foreground_mode"> 1024 </state>
                    <state id="background_mode"> 500 </state>
                    <state id="garage_mode"> 2048 </state>
                  </perStateThreshold>
            </packageSpecificThresholds>

            <!-- Application category specific thresholds. -->
            <appCategorySpecificThresholds>
                  <!-- One entry per supported application category -->
                  <perStateThreshold id="MEDIA">
                    <state id="foreground_mode"> 600 </state>
                    <state id="background_mode"> 700 </state>
                    <state id="garage_mode"> 1024 </state>
                  </perStateThreshold>

                  <perStateThreshold id="MAPS">
                    <state id="foreground_mode"> 800 </state>
                    <state id="background_mode"> 900 </state>
                    <state id="garage_mode"> 2048 </state>
                  </perStateThreshold>
            </appCategorySpecificThresholds>
      </ioOveruseConfiguration>
</resourceOveruseConfiguration>

עדכון ההגדרות של שימוש יתר באמצעות ממשקי ה-API של מערכת CarWatchdogManager

אפשר לספק את הגדרת ה-XML שלמעלה רק בקובץ האימג' של ה-build. אם יצרן ציוד מקורי (OEM) יבחר לעדכן את ההגדרות במכשיר אחרי פרסום ה-build, הוא יוכל להשתמש בממשקי ה-API הבאים כדי לבצע שינויים בהגדרות במכשיר.

  • מעניקים למבצע הקריאה החוזרת את ההרשאה Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG.
  • צריך להשתמש בתצורות הקיימות כדי לעדכן ולהגדיר את התצורות החדשות. משתמשים ב-API‏ CarWatchdogManager.getResourceOveruseConfigurations כדי לקבל את ההגדרות הקיימות. אם לא משתמשים בהגדרות קיימות, כל ההגדרות (כולל הגדרות מערכת והגדרות של צד שלישי) יימחקו, וזו לא המלצה.
  • מעדכנים את ההגדרות הקיימות עם השינויים של דלתא ומגדירים את ההגדרות החדשות. לא מעדכנים את ההגדרות של המערכת ושל רכיבי הצד השלישי.
  • משתמשים ב-API CarWatchdogManager.setResourceOveruseConfigurations כדי להגדיר את ההגדרות החדשות.
  • כדי לקבל ולהגדיר את ההגדרות של שימוש יתר ב-I/O בדיסק, משתמשים בדגל CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO.

לפניכם דוגמה להטמעה שמעדכנת את ההגדרות של שימוש יתר במשאבים:

void updateResourceOveruseConfigurations() {
    CarWatchdogManager manager =
        (CarWatchdogManager) car.getCarManager(Car.CAR_WATCHDOG_SERVICE);

    List<ResourceOveruseConfiguration> resourceOveruseConfigurations =
        manager.getResourceOveruseConfigurations(
            CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO);

    List<ResourceOveruseConfiguration> newResourceOveruseConfigurations =
            new List<>();
    ResourceOveruseConfiguration vendorConfiguration;
    for(ResourceOveruseConfiguration config : resourceOveruseConfigurations) {
        // Do not update the configurations of the system and third-party component types.
        if (config.getComponentType()
            != ResourceOveruseConfiguration.COMPONENT_TYPE_VENDOR) {
            newResourceOveruseConfigurations.add(config);
            continue;
        }
        vendorConfiguration = config;
    }

    if (vendorConfiguration == null) {
        ResourceOveruseConfiguration.Builder vendorConfigBuilder =
            new ResourceOveruseConfiguration.Builder();
        initializeConfig(vendorConfigBuilder);
        newResourceOveruseConfigurations.add(vendorConfigBuilder.build());
    } else {
        ResourceOveruseConfiguration newVendorConfig =
            updateConfig(vendorConfiguration);
        newResourceOveruseConfigurations.add(newVendorConfig);
    }
    int result = manager.setResourceOveruseConfigurations(
        newResourceOveruseConfigurations,

    if (result != CarWatchdogManager.RETURN_CODE_SUCCESS) {
        // Failed to set the resource overuse configurations.
    }
}

/** Sets the delta between the old configuration and the new configuration. */
ResourceOveruseConfiguration updateConfig(
    ResourceOveruseConfiguration oldConfiguration) {
    // Replace com.vendor.package.A with com.vendor.package.B in the safe-to-kill list.
    List<String> safeToKillPackages = oldConfiguration.getSafeToKillPackages();
    safeToKillPackages.remove("com.vendor.package.A");
    safeToKillPackages.add("com.vendor.package.B");

    ResourceOveruseConfiguration.Builder configBuilder =
        new ResourceOveruseConfiguration.Builder(
            oldConfiguration.getComponentType(),
            safeToKillPackages,
            oldConfiguration.getVendorPackagePrefixes(),
            oldConfiguration.getPackagesToAppCategoryTypes());

    configBuilder.addVendorPackagePrefixes("com.vendor.");
    configBuilder.addPackagesToAppCategoryTypes("com.vendor.package.B",
        ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MAPS);

    IoOveruseConfiguration oldIoConfiguration = oldConfiguration.getIoOveruseConfiguration();
    IoOveruseConfiguration.Builder ioConfigBuilder =
        new IoOveruseConfiguration.Builder(
            oldIoConfiguration.getComponentLevelThresholds(),
            oldIoConfiguration.getPackageSpecificThresholds(),
            oldIoConfiguration.getAppCategorySpecificThresholds(),
            oldIoConfiguration.getSystemWideThresholds());

    // Define the amount of bytes based on the flash memory specification, expected lifetime,
    // and estimated average amount of bytes written by a package during different modes.
    ioConfigBuilder.addPackageSpecificThresholds("com.vendor.package.B",
        new PerStateBytes(/* foregroundModeBytes= */ 2 * 1024 * 1024 * 1024,
                          /* backgroundModeBytes= */ 500 * 1024 * 1024,
                          /* garageModeBytes= */ 3 * 1024 * 1024 * 1024));


    return configBuilder.setIoOveruseConfiguration(ioConfigBuilder.build()).build();
}

אפליקציות שמבצעות מעקב אחר שימוש יתר במשאבים

ספקים ואפליקציות צד שלישי יכולים להאזין להתראות מ-Watchdog על שימוש יתר במשאבים ספציפיים לאפליקציה, או לבצע סקרים ב-CarWatchdogManager כדי לקבל נתונים סטטיסטיים על שימוש יתר במשאבים ספציפיים לאפליקציה ב-30 הימים האחרונים.

האזנה להתראות על שימוש יתר במשאבים

אפליקציות יכולות להטמיע מאזין לשימוש יתר במשאבים ולרשום את המאזין ב-CarWatchdogManager כדי לקבל התראות ספציפיות לאפליקציה כשהן חורגות מ-80% או מ-100% של ערכי הסף שלהן לשימוש יתר ב-I/O בדיסק. אפליקציות יכולות להשתמש בהתראות האלה כדי:

  • רישום ביומן של נתוני הסטטיסטיקה של שימוש יתר ב-I/O בדיסק לצורך ניתוח אופליין. מפתחי האפליקציות יכולים להשתמש ברישום ביומן כדי לנפות באגים בבעיה של שימוש יתר ב-I/O בדיסק.
  • מפחיתים את מספר פעולות הכתיבה של קלט/פלט בדיסק עד שמונהני השימוש יאופסו.

לקוח Java

  1. מטמיעים את ה-listener על ידי ירושה מ-CarWatchdogManager.ResourceOveruseListener:
    class ResourceOveruseListenerImpl implements
          CarWatchdogManager.ResourceOveruseListener {
                @Override
                public void onOveruse(
                      @NonNull ResourceOveruseStats resourceOveruseStats) {
                      // 1. Log/Upload resource overuse metrics.
                      // 2. Reduce writes until the counters reset.
    
                      IoOveruseStats ioOveruseStats = resourceOveruseStats.getIoOveruseStats();
                      // Stats period - [ioOveruseStats.getStartTime(), ioOveruseStats.getStartTime()
                      //   + ioOveruseStats.getDurationInSeconds()]
                      // Total I/O overuses - ioOveruseStats.getTotalOveruses()
                      // Total bytes written - ioOveruseStats.getTotalBytesWritten()
                      // Remaining write bytes for the current UTC calendar day -
                      //    ioOveruseStats.getRemainingWriteBytes()
                }
          }
    }
  2. רושמים את מופע המאזין באמצעות קריאה ל-CarWatchdogManager.addResourceOveruseListener
    private void addResourceOveruseListener() {
          CarWatchdogManager manager =
                (CarWatchdogManager) car.getCarManager(Car.CAR_WATCHDOG_SERVICE);
          // Choose a proper executor to handle resource overuse notifications.
          Executor executor = mContext.getMainExecutor();
          manager.addResourceOveruseListener(
                executor, CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
                mListenerImpl);
    }
  3. צריך לבטל את הרישום של מופע המאזין כשהאפליקציה מסיימת להאזין לאירועים הבאים:
    private void removeResourceOveruseListener() {
        CarWatchdogManager manager =
                (CarWatchdogManager) car.getCarManager(Car.CAR_WATCHDOG_SERVICE);
        mCarWatchdogManager.removeResourceOveruseListener(
              mListenerImpl);
    }

לקוח מקורי

  1. כוללים את carwatchdog_aidl_interface-ndk_platform ביחסי התלות של shared_libs בכלל ה-build.

    Android.bp

    cc_binary {
        name: "sample_native_client",
        srcs: [
            "src/*.cpp"
        ],
        shared_libs: [
            "carwatchdog_aidl_interface-ndk_platform",
            "libbinder_ndk",
        ],
        vendor: true,
    }
  2. מוסיפים מדיניות SELinux כדי לאפשר לדומיין השירות של הספק להשתמש ב-binder (מאקרו binder_user) ומוסיפים את דומיין השירות של הספק לדומיין הלקוח carwatchdog(carwatchdog_client_domain macro). הקוד שלמטה מיועד ל-sample_client.te ול-file_contexts.

    sample_client.te

    type sample_client, domain;
    type sample_client_exec, exec_type, file_type, vendor_file_type;
    
    carwatchdog_client_domain(sample_client)
    
    init_daemon_domain(sample_client)
    binder_use(sample_client)

    file_contexts

    /vendor/bin/sample_native_client  u:object_r:sample_client_exec:s0
  3. מטמיעים את המאזין לשימוש יתר במשאבים על ידי ירושה מ-BnResourceOveruseListener. משנים את הערך של BnResourceOveruseListener::onOveruse כדי לטפל בהתראות על שימוש יתר במשאבים.

    ResourceOveruseListenerImpl.h

    class ResourceOveruseListenerImpl : public BnResourceOveruseListener {
    public:
        ndk::ScopedAStatus onOveruse(
            ResourceOveruseStats resourceOveruseStats) override;
    
    private:
        void initialize();
        void terminate();
    
        std::shared_ptr<ICarWatchdog> mWatchdogServer;
        std::shared_ptr<IResourceOveruseListener> mListener;
    }

    ResourceOveruseListenerImpl.cpp

    ndk::ScopedAStatus ResourceOveruseListenerImpl::onOveruse(
          ResourceOveruseStats resourceOveruseStats) {
    
          // 1. Log/Upload resource overuse metrics.
          // 2. Reduce writes until the counters reset.
    
          if (stats.getTag() != ResourceOveruseStats::ioOveruseStats) {
                // Received resourceOveruseStats doesn't contain I/O overuse stats.
          }
    
          const IoOveruseStats& ioOveruseStats = stats.get();
          // Stats period - [ioOveruseStats.startTime,
          //   ioOveruseStats.startTime + ioOveruseStats.durationInSeconds]
          // Total I/O overuses - ioOveruseStats.totalOveruses
          // Total bytes written - ioOveruseStats.writtenBytes
          // Remaining write bytes for the current UTC calendar day -
          //    ioOveruseStats.remainingWriteBytes
    
          return ndk::ScopedAStatus::ok();
    }
  4. מפעילים מאגר חוטים של binder ומרשמים את המאזין לשימוש יתר במשאבים אצל שרת watchdog. שרת Watchdog רשום בשם השירות android.automotive.watchdog.ICarWatchdog/default.

    main.cpp

    int main(int argc, char** argv) {
        ABinderProcess_setThreadPoolMaxThreadCount(1);
        ABinderProcess_startThreadPool();
        std::shared_ptr<ResourceOveruseListenerImpl> listener =
            ndk::SharedRefBase::make<ResourceOveruseListenerImpl>();
    
        // The listener is added in initialize().
        listener->initialize();
    
        ... Run service ...
    
        // The listener is removed in terminate().
        listener->terminate();
    }

    ResourceOveruseListenerImpl.cpp

    void ResourceOveruseListener::initialize() {
        ndk::SpAIBinder binder(AServiceManager_getService(
                "android.automotive.watchdog.ICarWatchdog/default"));
        std::shared_ptr<ICarWatchdog> server = ICarWatchdog::fromBinder(binder);
        mWatchdogServer = server;
    
        std::shared_ptr<IResourceOveruseListener> listener =
            IResourceOveruseListener::fromBinder(this->asBinder());
        mWatchdogServer->addResourceOveruseListener(
          std::vector<int>{ResourceType.IO}, listener);
        mListener = listener;
    }
    
    void ResourceOveruseListener::terminate() {
        mWatchdogServer->removeResourceOveruseListener(mListener);
    }

סקרים של נתוני סטטיסטיקה על שימוש יתר במשאבים

אפליקציות יכולות לבצע סקרים ב-CarWatchdogManager כדי לקבל את נתוני ה-ATS של שימוש יתר ב-I/O ספציפיים לאפליקציה ב-30 הימים האחרונים.

לקוח Java

משתמשים ב-CarWatchdogManager.getResourceOveruseStats כדי לקבל את הנתונים הסטטיסטיים על שימוש יתר במשאבים. מעבירים את הדגל CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO כדי לקבל את הנתונים הסטטיסטיים של שימוש יתר ב-I/O בדיסק.

private void getResourceOveruseStats() {
      CarWatchdogManager manager =
            (CarWatchdogManager) car.getCarManager(Car.CAR_WATCHDOG_SERVICE);

      // Returns resource overuse stats with I/O overuse stats for the past
      // 7 days. Stats are available for up to the past 30 days.
      ResourceOveruseStats resourceOveruseStats =
            mCarWatchdogManager.getResourceOveruseStats(
                  CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
                  CarWatchdogManager.STATS_PERIOD_PAST_7_DAYS);

      IoOveruseStats ioOveruseStats = resourceOveruseStats.getIoOveruseStats();
      // Stats period - [ioOveruseStats.getStartTime(), ioOveruseStats.getStartTime()
      //   + ioOveruseStats.getDurationInSeconds()]
      // Total I/O overuses - ioOveruseStats.getTotalOveruses()
      // Total bytes written - ioOveruseStats.getTotalBytesWritten()
      // Remaining write bytes for the UTC calendar day -
      //    ioOveruseStats.getRemainingWriteBytes()
}

לקוח מקורי

משתמשים ב-CarWatchdogServer.getResourceOveruseStats כדי לקבל את הנתונים הסטטיסטיים על שימוש יתר במשאבים. מעבירים את המאפיין ResourceType.IO כדי לאחזר נתונים סטטיסטיים על שימוש יתר ב-I/O בדיסק.

void getResourceOveruseStats() {
      ndk::SpAIBinder binder(AServiceManager_getService(
            "android.automotive.watchdog.ICarWatchdog/default"));
      std::shared_ptr<ICarWatchdog> server = ICarWatchdog::fromBinder(binder);
      // Returns the stats only for the current UTC calendar day.
      const std::vector<ResourceOveruseStats> resourceOveruseStats;
      ndk::ScopedAStatus status = server.getResourceOveruseStats(
            std::vector<int>{ResourceType.IO}, &resourceOveruseStats);
      if (!status.isOk()) {
            // Failed to get the resource overuse stats.
            return;
      }

      for (const auto& stats : resourceOveruseStats) {
            if (stats.getTag() != ResourceOveruseStats::ioOveruseStats) {
                  continue;
            }
            const IoOveruseStats& ioOveruseStats = stats.get();
            // Stats period - [ioOveruseStats.startTime,
            //   ioOveruseStats.startTime + ioOveruseStats.durationInSeconds]
            // Total I/O overuses - ioOveruseStats.totalOveruses
            // Total bytes written - ioOveruseStats.writtenBytes
            // Remaining write bytes for the current UTC calendar day -
            //   ioOveruseStats.remainingWriteBytes
      }
}

חוויית משתמש במקרה של שימוש יתר במשאבים

בקטעים הבאים מתוארת חוויית המשתמש כשמתרחשת שימוש יתר במשאבים.

הגדרת העדיפות לביצועי האפליקציות

בדף הגדרות של האפליקציה יש הגדרות ל-Prioritize app performance (ראו את התמונה שבהמשך), שמאפשרות למשתמשים לתת עדיפות לביצועים של האפליקציה על פני הביצועים של המערכת והחומרה לטווח ארוך. ההגדרה הזו זמינה רק לאפליקציות שאפשר לסגור בבטחה אם הן משתמשות יותר מדי במשאבים. אחרת, ההגדרה הזו מושבתת. כשההגדרה הזו מושבתת (ברירת המחדל) באפליקציה, יכול להיות שהאפליקציה תיסגר אם תהיה שימוש יתר במשאבים. אחרת, האפליקציה לא תיסגר בגלל שימוש יתר במשאבים.

כשהמשתמש מפעיל את ההגדרה הזו, תיבת הדו-שיח לאישור הבאה מתארת את ההשלכות של הפעלת ההגדרה:

אחרי 90 יום, ההגדרה הזו מתאפסת באופן אוטומטי לברירת המחדל. אפשר לשנות את המגבלה היומית באמצעות אפליקציית שכבת-על של RRO באמצעות watchdogUserPackageSettingsResetDays, עד 180 יום לכל היותר. למידע נוסף, ראו שינוי הערך של משאבים של אפליקציה בזמן הריצה. אפשר לכלול את תג שכבת-העל לדוגמה הבא ב-AndroidManifest.xml:

<overlay android:priority="<insert-value>"
      android:targetPackage="com.android.car.updatable"
      android:targetName="CarServiceCustomization"
      android:resourcesMap="@xml/overlays" />

ב-res/values/config.xml:

<resources>
  <integer name="watchdogUserPackageSettingsResetDays">value</integer>
</resources>

ב-res/xml/overlays.xml:

<overlay>
  <item target="integer/watchdogUserPackageSettingsResetDays" value="@integer/watchdogUserPackageSettingsResetDays" />
</overlay>

ההגדרה 'אפליקציות שמשפיעות על הביצועים'

באפליקציית הגדרות יש קטע אפליקציות שמשפיעות על הביצועים (ראו איור 1). כשלוחצים עליו, מוצגת רשימה של אפליקציות שהוגבל השימוש בהן בגלל שימוש מוגזם בזיכרון הפלאש, ומשפיעות לרעה על ביצועי המערכת. הדבר עומד בדרישות של CDD 3.5.1 [C-1-1].

אפליקציות שמשפיעות על הביצועים

איור 1. אפליקציות שמשפיעות על הביצועים.

כאן מפורטות אפליקציות שנסגרו בגלל שימוש יתר במשאבים (ראו איור 2). אפשר לתת עדיפות לאפליקציות שמופיעות ברשימה. מידע נוסף זמין במאמר הגדרת העדיפות לפי ביצועי האפליקציות.

רשימת האפליקציות שהושעו בגלל שימוש יתר במשאבים

איור 2. רשימת האפליקציות שהושעו בגלל שימוש יתר במשאבים.

הודעה למשתמש

אם אפליקציה או שירות משתמשים באופן חוזר באינטראקציה קלט/פלט (I/O) בדיסק (למשל, כותבים נתונים בדיסק מעבר לסף המוגדר) בפרק זמן מסוים, ואפשר לסגור אותם בבטחה בגלל שימוש יתר במשאבים, המשתמש יקבל הודעה אחרי שהרכב יעבור למצב 'אישור הסחת דעת של הנהג'.

ההתראה הראשונה למשתמש (במהלך נסיעה) מוצגת כהודעה מראש, וההתראות האחרות מוצגות במרכז ההתראות.

לדוגמה, אם אפליקציה משתמשת באופן חוזר ונשנה ב-I/O בדיסק, המשתמש יקבל את ההתראה הבאה:

  • כשהמשתמש לוחץ על הלחצן העדפת האפליקציה, נפתח דף ההגדרות של האפליקציה, שבו המשתמש יכול להפעיל או להשבית את ההגדרה העדפת ביצועי האפליקציה.
  • כשהמשתמש לוחץ על הלחצן Disable app, האפליקציה מושבתת עד שהמשתמש מפעיל אותה או מפעיל אותה בדף ההגדרות של האפליקציה.
  • באפליקציות שלא ניתן להסיר, הלחצן השבתת האפליקציה מוחלף בלחצן הסרת האפליקציה. כאשר המשתמש לוחץ על הלחצן Uninstall app (הסרת האפליקציה), נפתח דף ההגדרות של האפליקציה, שממנו המשתמש יכול להסיר את האפליקציה.

המלצה להטמעה של מרכז האפליקציות

כשאפליקציות מושבתות בגלל שימוש יתר במשאבים, הן נעלמות מאפליקציית מרכז האפליקציות שמוגדרת כברירת מחדל, כי CarService מעדכן את מצב ההפעלה של האפליקציות כ-PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED. יצרני ציוד מקורי (OEM) צריכים לעדכן את ההטמעה של מרכז האפליקציות המובנה כדי להציג את האפליקציות האלה כחריגות, כדי שהמשתמשים יוכלו להשתמש בהן במקרה הצורך. בהתאם לגרסה של ה-build, אלה ההמלצות הבאות:

השקת Android SC V2