تصحيح أخطاء الملفات الشخصية المرجعية

يعرض هذا المستند أفضل الممارسات للمساعدة في تشخيص المشكلات وضمان تعمل الملفات الشخصية الأساسية على نحو سليم لتحقيق أكبر فائدة.

مشاكل الإصدار

في حال نسخ مثال "الملفات الشخصية الأساسية" في قسم Now in Android (الآن في Android) نموذج تطبيق، قد تواجه تعذُّر الاختبار أثناء مَهمّة "الملف الشخصي الأساسي". الإشارة إلى عدم إمكانية إجراء الاختبارات على المحاكي:

./gradlew assembleDemoRelease
Starting a Gradle Daemon (subsequent builds will be faster)
Calculating task graph as no configuration cache is available for tasks: assembleDemoRelease
Type-safe project accessors is an incubating feature.

> Task :benchmarks:pixel6Api33DemoNonMinifiedReleaseAndroidTest
Starting 14 tests on pixel6Api33

com.google.samples.apps.nowinandroid.foryou.ScrollForYouFeedBenchmark > scrollFeedCompilationNone[pixel6Api33] FAILED
        java.lang.AssertionError: ERRORS (not suppressed): EMULATOR
        WARNINGS (suppressed):
        ...

تحدث الإخفاقات لأن Now في Android يستخدم جهازًا مُدارًا من Gradle إنشاء الملفات الشخصية الأساسية ومن المتوقع حدوث الإخفاقات، لأنك عادةً ما عدم تشغيل مقاييس الأداء على محاكي ومع ذلك، نظرًا لأنك لا جمع مقاييس الأداء عند إنشاء ملفات شخصية أساسية، يمكنك مجموعة "الملف الشخصي الأساسي" على أدوات المحاكاة لتيسير الوصول إليها. لاستخدام "المقياس الأساسي" باستخدام المحاكي، يمكنك تنفيذ عملية الإنشاء والتثبيت من سطر الأوامر وتعيين وسيطة لتفعيل قواعد الملفات الشخصية الأساسية:

installDemoRelease -Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile

ويمكنك بدلاً من ذلك إنشاء إعدادات تشغيل مخصّصة في "استوديو Android" من أجل تفعيل الملفات الشخصية غير المرجعية على أدوات المحاكاة من خلال اختيار تشغيل > تعديل الإعدادات:

أضِف إعدادات تشغيل مخصّصة لإنشاء ملفات شخصية أساسية في تطبيق Now على Android
الشكل 1. أضِف إعدادات تشغيل مخصّصة لإنشاء "المقياس الأساسي". الملفات الشخصية الآن في Android

مشاكل التثبيت

تأكَّد من أنّ ملف APK أو AAB الذي تنشئه هو من إصدار إصدار يتضمن الملفات الشخصية المرجعية وتتمثل أسهل طريقة للتحقق من ذلك في فتح APK في "استوديو Android" من خلال النقر على إنشاء > تحليل APK، مما يؤدي إلى فتح APK، وتبحث عن الملف الشخصي في /assets/dexopt/baseline.prof الملف:

البحث عن "ملف شخصي أساسي" باستخدام عارض APK في "استوديو Android"
الشكل 2. ابحث عن ملف شخصي أساسي باستخدام عارض APK في "استوديو Android"
.

ويجب تجميع الملفات الشخصية الأساسية على الجهاز الذي يُشغِّل التطبيق. للاثنين عمليات تثبيت متجر التطبيقات والتطبيقات المثبتة باستخدام PackageInstaller، يحدث التجميع على الجهاز فقط كجزء من التطبيق التثبيت. عند تثبيت التطبيق من مصدر غير معروف من "استوديو Android" باستخدام أدوات سطر الأوامر، فإن مكتبة Jetpack ProfileInstaller هي المسئول عن إدراج الملفات الشخصية في قائمة الانتظار للتجميع خلال وعملية تحسين DEX للخلفية. في هذه الحالات، إذا أردت التأكد من أنّ يتم استخدام الملفات الشخصية المرجعية، قد تحتاج إلى: فرض تجميع الملفات الشخصية الأساسية: يتيح لك ProfileVerifier الاستعلام عن حالة تثبيت الملف الشخصي وتجميعه، كما هو موضح في في المثال التالي:

Kotlin

private const val TAG = "MainActivity"

class MainActivity : ComponentActivity() {
  ...
  override fun onResume() {
    super.onResume()
    lifecycleScope.launch {
      logCompilationStatus()
    }
  }

  private suspend fun logCompilationStatus() {
     withContext(Dispatchers.IO) {
        val status = ProfileVerifier.getCompilationStatusAsync().await()
        when (status.profileInstallResultCode) {
            RESULT_CODE_NO_PROFILE ->
                Log.d(TAG, "ProfileInstaller: Baseline Profile not found")
            RESULT_CODE_COMPILED_WITH_PROFILE ->
                Log.d(TAG, "ProfileInstaller: Compiled with profile")
            RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION ->
                Log.d(TAG, "ProfileInstaller: Enqueued for compilation")
            RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING ->
                Log.d(TAG, "ProfileInstaller: App was installed through Play store")
            RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST ->
                Log.d(TAG, "ProfileInstaller: PackageName not found")
            RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ ->
                Log.d(TAG, "ProfileInstaller: Cache file exists but cannot be read")
            RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE ->
                Log.d(TAG, "ProfileInstaller: Can't write cache file")
            RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION ->
                Log.d(TAG, "ProfileInstaller: Enqueued for compilation")
            else ->
                Log.d(TAG, "ProfileInstaller: Profile not compiled or enqueued")
        }
    }
}

Java

public class MainActivity extends ComponentActivity {

    private static final String TAG = "MainActivity";

    @Override
    protected void onResume() {
        super.onResume();

        logCompilationStatus();
    }

    private void logCompilationStatus() {
         ListeningExecutorService service = MoreExecutors.listeningDecorator(
                Executors.newSingleThreadExecutor());
        ListenableFuture<ProfileVerifier.CompilationStatus> future =
                ProfileVerifier.getCompilationStatusAsync();
        Futures.addCallback(future, new FutureCallback<>() {
            @Override
            public void onSuccess(CompilationStatus result) {
                int resultCode = result.getProfileInstallResultCode();
                if (resultCode == RESULT_CODE_NO_PROFILE) {
                    Log.d(TAG, "ProfileInstaller: Baseline Profile not found");
                } else if (resultCode == RESULT_CODE_COMPILED_WITH_PROFILE) {
                    Log.d(TAG, "ProfileInstaller: Compiled with profile");
                } else if (resultCode == RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION) {
                    Log.d(TAG, "ProfileInstaller: Enqueued for compilation");
                } else if (resultCode == RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING) {
                    Log.d(TAG, "ProfileInstaller: App was installed through Play store");
                } else if (resultCode == RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST) {
                    Log.d(TAG, "ProfileInstaller: PackageName not found");
                } else if (resultCode == RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ) {
                    Log.d(TAG, "ProfileInstaller: Cache file exists but cannot be read");
                } else if (resultCode
                        == RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE) {
                    Log.d(TAG, "ProfileInstaller: Can't write cache file");
                } else if (resultCode == RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION) {
                    Log.d(TAG, "ProfileInstaller: Enqueued for compilation");
                } else {
                    Log.d(TAG, "ProfileInstaller: Profile not compiled or enqueued");
                }
            }

            @Override
            public void onFailure(Throwable t) {
                Log.d(TAG,
                        "ProfileInstaller: Error getting installation status: " + t.getMessage());
            }
        }, service);
    }
}

تقدم رموز النتائج التالية تلميحات عن سبب بعض المشكلات:

RESULT_CODE_COMPILED_WITH_PROFILE
يتم تثبيت الملف الشخصي وتجميعه واستخدامه عند تشغيل التطبيق. هذا النمط هو النتيجة التي تريد الحصول عليها.
RESULT_CODE_ERROR_NO_PROFILE_EMBEDDED
لم يتم العثور على أي ملف شخصي في ملف APK أو AAB قيد التشغيل. تأكد من استخدام إصدار نسخة تتضمّن الملفات الشخصية الأساسية في حال ظهور هذا الخطأ، تحتوي حزمة APK على ملف شخصي.
RESULT_CODE_NO_PROFILE
لم يتم تثبيت أي ملف شخصي لهذا التطبيق عند تثبيت التطبيق من خلال التطبيق. أو مدير الحزمة. السبب الرئيسي لحدوث رمز الخطأ هو أن ملف التعريف لم يتم تشغيل أداة التثبيت بسبب إيقاف ProfileInstallerInitializer. يُرجى ملاحظة أنّه عند الإبلاغ عن هذا الخطأ، كان لا يزال هناك ملف شخصي مضمّن في التطبيق. عند عدم العثور على ملف شخصي مضمّن، يتم عرض رمز الخطأ RESULT_CODE_ERROR_NO_PROFILE_EMBEDDED.
RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION
تم العثور على ملف شخصي في APK أو AAB، وتمت إضافته إلى قائمة الانتظار للتجميع. عندما تم تثبيت ملف التعريف بواسطة ProfileInstaller، وهو في قائمة انتظار التجميع في المرة التالية التي يشغِّل فيها النظام تحسين DEX في الخلفية. الملف الشخصي ليس نشطة إلى أن تكتمل عملية التجميع. لا تحاول قياس القيمة المرجعية الملفات الشخصية إلى أن تكتمل عملية التجميع. قد تحتاج إلى فرض تجميع الملفات الشخصية الأساسية: لن يحدث هذا الخطأ عندما يتم تثبيت التطبيق من متجر التطبيقات أو مدير الحزم على الأجهزة التي تعمل الإصدار 9 من نظام التشغيل Android (API 28) والإصدارات الأحدث، لأنّ التجميع أثناء التثبيت.
RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING
يتم تثبيت ملف شخصي غير متطابق ويتم تجميع التطبيق باستخدامه. تكون هذه نتيجة التثبيت من خلال متجر Google Play أو مدير الحزم. يُرجى العِلم أنّ هذه النتيجة تختلف عن RESULT_CODE_COMPILED_WITH_PROFILE للأسباب التالية: فإن الملف الشخصي غير المطابق سيجمع فقط أي طرق لا تزال مشتركة بين الملف الشخصي والتطبيق. الملف الشخصي أصغر فعليًا من ومتوقعًا، وسيتم تجميع عدد أقل من الطرق التي تم تضمينها في المجموعة المرجعية ملفك التجاري.
RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE
لم يتمكن ProfileVerifier من كتابة ملف ذاكرة التخزين المؤقت لنتائج التحقق. يمكن أن قد يحدث بسبب حدوث خطأ في أذونات مجلد التطبيق أو إذا عدم توفّر مساحة كافية على القرص على الجهاز
RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION
يتوافق تطبيق
ProfileVerifieris running on an unsupported API version of Android. ProfileVerifier مع نظام التشغيل Android 9 (المستوى 28 من واجهة برمجة التطبيقات) والإصدارات الأحدث فقط.
RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST
يتم تشغيل PackageManager.NameNotFoundException عند الاستعلام عن PackageManager لحزمة التطبيق من المفترض أن يحدث هذا نادرًا. تجربة إلغاء تثبيت التطبيق وإعادة تثبيت كل التطبيقات
RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ
هناك ملف ذاكرة تخزين مؤقت لنتائج إثبات الملكية، ولكن لا يمكن قراءته. هذا النمط نادرًا ما يحدث. حاول إلغاء تثبيت التطبيق وإعادة تثبيت كل شيء.

استخدام ProfileVerifier في مرحلة الإنتاج

في الإصدار العلني، يمكنك استخدام ProfileVerifier مع مكتبات إعداد تقارير الإحصاءات، مثل إحصاءات Google لبرنامج Firebase إنشاء أحداث إحصاءات تشير إلى حالة الملف الشخصي. على سبيل المثال، ينبهك سريعًا إذا تم طرح إصدار جديد من التطبيق لا يحتوي على الملفات الشخصية المرجعية

تجميع الملفات الشخصية الأساسية

إذا كانت حالة تجميع الملفات الشخصية الأساسية RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION، يمكنك فرض الميزة فورًا. التجميع باستخدام adb:

adb shell cmd package compile -r bg-dexopt PACKAGE_NAME

التحقّق من حالة التجميع بدون ProfileVerifier

إذا كنت لا تستخدم ProfileVerifier، يمكنك التحقّق من حالة التجميع باستخدام adb، مع أنّه لا يقدّم إحصاءات مفصّلة مثل ProfileVerifier:

adb shell dumpsys package dexopt | grep -A 2 PACKAGE_NAME

يؤدي استخدام adb إلى إنتاج نتيجة مشابهة لما يلي:

  [com.google.samples.apps.nowinandroid.demo]
    path: /data/app/~~dzJiGMKvp22vi2SsvfjkrQ==/com.google.samples.apps.nowinandroid.demo-7FR1sdJ8ZTy7eCLwAnn0Vg==/base.apk
      arm64: [status=speed-profile] [reason=bg-dexopt] [primary-abi]
        [location is /data/app/~~dzJiGMKvp22vi2SsvfjkrQ==/com.google.samples.apps.nowinandroid.demo-7FR1sdJ8ZTy7eCLwAnn0Vg==/oat/arm64/base.odex]

تشير قيمة الحالة إلى حالة تجميع الملف الشخصي وهي إحدى القيم التالية:

حالة التحويل البرمجي المعنى
speed‑profile يوجد ملف تعريف تم تجميعه ويتم استخدامه.
verify لا يوجد ملف تعريف مجمعة.

لا تعني الحالة verify أنّ حزمة APK أو AAB لا تحتوي على ملف شخصي. لأنه يمكن وضعه في قائمة الانتظار للتجميع عن طريق تحسين DEX التالي في الخلفية المهمة.

تشير قيمة السبب إلى ما يؤدي إلى تجميع الملف الشخصي يتم عرض إحدى القيم التالية:

السبب المعنى
install‑dm جمعت Google ملفًا شخصيًا مرجعيًا يدويًا أو من إعداد Google. يمكنك تشغيل المحتوى عندما يكون التطبيق مثبّتًا.
bg‑dexopt تم تجميع ملف شخصي عندما كان جهازك غير نشِط لفترة قصيرة. قد يكون هذا ملف تعريف شخصي أو قد يكون ملفًّا التي يتم جمعها أثناء استخدام التطبيق.
cmdline تم تشغيل التحويل باستخدام adb. قد يكون هذا ملف تعريف شخصي أو قد يكون ملفًّا التي يتم جمعها أثناء استخدام التطبيق.

مشاكل في الأداء

يعرض هذا القسم بعضًا من أفضل الممارسات للتحديد وقياس الأداء بشكل صحيح الملفات الشخصية الأساسية للاستفادة منها إلى أقصى حد.

قياس أداء مقاييس بدء التشغيل بشكل صحيح

ستكون الملفات الشخصية الأساسية أكثر فعالية إذا كانت مقاييس الشركات الناشئة: محددة جيدًا. إنّ المقياسَين الرئيسيَّين هما الوقت المُستغرَق للعرض الأولي (TTID). الوقت المُستغرَق للعرض الكامل (TTFD):

يحدث TTID عندما يرسم التطبيق أول إطار له. من المهم أن تجعل هذا قصيرًا قدر الإمكان، لأنّ عرض عنصر ما يوضّح للمستخدم أنّ التطبيق قيد التشغيل. يمكنك أيضًا عرض مؤشر تقدم غير محدد لإظهار أن التطبيق سريع الاستجابة.

يشير مصطلح TTFD إلى الوقت الذي يمكن فيه التفاعل مع التطبيق. من المهم أن تضع هذا قصير قدر الإمكان لتجنب استياء المستخدم. إذا قمت بالإشارة بشكل صحيح هذا يعني أنك تخبر النظام بأن الرمز الذي يتم تشغيله في طريقه إلى TTFD في مرحلة بدء تشغيل التطبيق. يزيد احتمال أن يضع النظام هذا الرمز في الملف الشخصي. نتيجة لذلك.

ويجب إبقاء كل من TTID وTTFD منخفضَين قدر الإمكان لكي يبدو تطبيقك مستجيبًا.

يمكن للنظام اكتشاف TTID وعرضه في Logcat والإبلاغ عنه كجزء من البرنامج. ومقاييس أداء الشركات الناشئة ومع ذلك، يتعذر على النظام تحديد TTFD، مسئولية التطبيق عن الإبلاغ عند وصوله إلى واجهة تفاعلية مرسومة بالكامل الولاية. يمكنك إجراء ذلك من خلال الاتصال بالرقم reportFullyDrawn() ReportDrawn إذا كنت تستخدم Jetpack Compose. إذا كان لديك عدة المهام التي في الخلفية يجب إكمالها جميعًا قبل احتساب التطبيق بشكل كامل مرسومة، يمكنك استخدام FullyDrawnReporter، كما هو موضح في تحسين ودقة توقيت بدء التشغيل.

الملفات الشخصية للمكتبة والملفات الشخصية المخصّصة

وعند قياس تأثير الملفات الشخصية، قد يكون من الصعب فصل مزايا الملفات الشخصية للتطبيق من الملفات الشخصية التي تساهم بها المكتبات، مثل مكتبات Jetpack. عند إنشاء حزمة APK، يضيف المكوّن الإضافي لنظام Gradle المتوافق مع Android أي في ملحقات المكتبة وكذلك في ملفك الشخصي المخصص. هذا جيد لتحسين الأداء العام، ويُنصح به مع إصدارات الإصدارات. ومع ذلك، فإنه يجعل من الصعب قياس مقدار مكاسب الأداء الإضافية التي تأتي من ملفك الشخصي المخصص.

طريقة سريعة للاطلاع يدويًا على التحسين الإضافي الذي يقدمه حسابك هو إزالته، وإدارة مقاييس الأداء. ثم استبدله وشغِّل للمقاييس مرة أخرى. وستعرض لك المقارنة بين الاثنين التحسينات التي أجراها والملفات الشخصية للمكتبة فقط والملفات الشخصية للمكتبة بالإضافة إلى ملفك الشخصي المخصص.

تتوفّر طريقة تلقائية لمقارنة الملفات الشخصية من خلال إنشاء نسخة جديدة من الإصدار على الملفات الشخصية للمكتبة فقط وليس على ملفك الشخصي المخصّص. مقارنة من هذه الصيغة إلى صيغة الإصدار التي تتضمن الملفات الشخصية للمكتبة وملفاتك الشخصية المخصصة. يوضح المثال التالي كيف لإعداد خيار يتضمّن الملفات الشخصية للمكتبة فقط إضافة صيغة جديدة باسم releaseWithoutCustomProfile في وحدة المستهلك في ملفك الشخصي، وهي عادةً وحدة تطبيقك:

Kotlin

android {
  ...
  buildTypes {
    ...
    // Release build with only library profiles.
    create("releaseWithoutCustomProfile") {
      initWith(release)
    }
    ...
  }
  ...
}
...
dependencies {
  ...
  // Remove the baselineProfile dependency.
  // baselineProfile(project(":baselineprofile"))
}

baselineProfile {
  variants {
    create("release") {
      from(project(":baselineprofile"))
    }
  }
}

Groovy

android {
  ...
  buildTypes {
    ...
    // Release build with only library profiles.
    releaseWithoutCustomProfile {
      initWith(release)
    }
    ...
  }
  ...
}
...
dependencies {
  ...
  // Remove the baselineProfile dependency.
  // baselineProfile ':baselineprofile"'
}

baselineProfile {
  variants {
    release {
      from(project(":baselineprofile"))
    }
  }
}

يزيل مثال الرمز السابق تبعية baselineProfile من جميع خيارات المنتجات وتطبيقها بشكل انتقائي على خيار المنتج release فقط. قد يبدو من البديهي أن ملفات المكتبة الشخصية لا تزال تتم إضافتها عندما تتم إزالة الاعتمادية على وحدة منتِج الملف الشخصي. ومع ذلك، فإن هذه الوحدة مسؤولة فقط عن إنشاء ملف تعريف مخصص. نظام Gradle المتوافق مع Android لا يزال المكوّن الإضافي قيد التشغيل لجميع المتغيرات، وهو مسؤول عن تضمين ملفات المكتبة الشخصية.

عليك أيضًا إضافة الصيغة الجديدة إلى وحدة إنشاء الملفات الشخصية. في هذه الدورة، على سبيل المثال، تُسمى وحدة المنتِج :baselineprofile.

Kotlin

android {
  ...
    buildTypes {
      ...
      // Release build with only library profiles.
      create("releaseWithoutCustomProfile") {}
      ...
    }
  ...
}

Groovy

android {
  ...
    buildTypes {
      ...
      // Release build with only library profiles.
      releaseWithoutCustomProfile {}
      ...
    }
  ...
}

عند تشغيل مقياس الأداء من "استوديو Android"، اختَر صيغة واحدة (releaseWithoutCustomProfile) لقياس الأداء من خلال المكتبة فقط أو اختيار صيغة release لقياس الأداء من خلال المكتبة والملفات الشخصية المخصصة.

تجنُّب بدء تشغيل التطبيق المرتبط بوحدات الإدخال والإخراج

إذا كان تطبيقك يُجري العديد من مكالمات وحدات الإدخال والإخراج (I/O) أو اتصالات الشبكات أثناء بدء التشغيل، عليك اتّباع الخطوات التالية: يمكن أن يؤثر ذلك سلبًا على وقت بدء تشغيل التطبيق ودقة بدء التشغيل لقياس الأداء. يمكن أن تستغرق هذه المكالمات الكبيرة فترات زمنية غير محدّدة والتي يمكن أن تختلف بمرور الوقت وحتى بين التكرارات للمقياس نفسه. مؤتمر I/O تكون الاتصالات أفضل بشكل عام من اتصالات الشبكة، حيث يمكن يتأثر بعوامل خارجية عن الجهاز وعلى الجهاز نفسه. تجنب الاتصال بالشبكة أثناء بدء التشغيل. استخدِم وحدات الإدخال والإخراج في الحالات التي لا مفرّ منها.

ننصحك بجعل بنية تطبيقك تتوافق مع بدء تشغيل التطبيق بدون الاتصال بشبكة طلبات وحدات الإدخال والإخراج، حتى لو تم استخدامها فقط عند قياس أداء بدء التشغيل يساعد هذا في ضمان أقل تباين ممكن بين التكرارات المختلفة لمقاييس الأداء.

إذا كان تطبيقك يستخدم Hilt، يمكنك تقديم ملفات وهمية مرتبطة بوحدات الإدخال والإخراج. عمليات التنفيذ عند قياس الأداء في Micromic and Hilt.

تغطية جميع رحلات المستخدم المهمة

من المهم أن تغطي بدقة جميع رحلات المستخدم المهمة في إنشاء الملفات الشخصية الأساسية لن يتم تناول أي رحلات مستخدم لم يتم تناولها تم تحسينها بواسطة الملفات الشخصية من الأشخاص الذين لم يروا الإعلانات تشمل الملفات الشخصية المرجعية الأكثر فاعلية جميع رحلات المستخدم الشائعة من الشركات الناشئة، بالإضافة إلى تجربة المستخدم داخل التطبيق الحساس للأداء رحلات مثل قوائم التمرير.