التحقق من سلوك التطبيق في وقت تشغيل Android (ART)

وقت تشغيل Android (ART) هو وقت التشغيل التلقائي للأجهزة التي تعمل بنظام التشغيل Android 5.0 (مستوى واجهة برمجة التطبيقات 21) والإصدارات الأحدث. توفّر بيئة التشغيل هذه عددًا من الميزات التي تعمل على تحسين أداء وسلاسة نظام Android الأساسي وتطبيقاته. يمكنك العثور على مزيد من المعلومات حول ميزات ART الجديدة في تقديم ART.

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

معالجة مشاكل جمع البيانات غير المرغوب فيها (GC)

ضمن Dalvik، تجد التطبيقات في كثير من الأحيان أنه من المفيد إجراء مكالمات System.gc() لطلب جمع البيانات المهملة (GC). يجب أن يكون هذا أقل أهمية بكثير مع ART، خاصةً إذا كنت تستدعي جمع البيانات لمنع النوع GC_FOR_ALLOC مرة أخرى أو لتقليل التجزئة. يمكنك معرفة بيئة التشغيل المستخدَمة عبر الاتصال بالرقم System.getProperty("java.vm.version"). إذا كانت ART قيد الاستخدام، تكون قيمة الخاصية يبلغ "2.0.0" أو أعلى.

يستخدم ART أداة تجميع النسخ المتزامن (CC) التي تعمل بشكل متزامن على ضغط كومة Java. لهذا السبب، يجب تجنب استخدام أساليب التي لا تتوافق مع ضغط البيانات المهملة (مثل حفظ المؤشرات في كائن المثيل). وهذا مهم بشكل خاص للتطبيقات التي تستخدم واجهة Java الأصلية (JNI). لمزيد من المعلومات، اطّلِع على منع مشاكل JNI.

منع مشاكل JNI

إنّ سجل JNI الخاص بـ ART أكثر صرامة إلى حد ما من دالفيك. إنها فكرة جيدة بشكل خاص استخدام وضع CheckJNI لاكتشاف المشكلات الشائعة. إذا كان تطبيقك يستخدم لغة C/C++ التعليمة البرمجية، فيجب عليك مراجعة المقالة التالية:

تصحيح الأخطاء Android JNI مع CheckJNI

التحقّق من رمز JNI بحثًا عن مشاكل في جمع البيانات غير المرغوب فيها

قد يقوم مُجمِّع النسخ المتزامن (CC) بنقل العناصر في الذاكرة للضغط. إذا كنت تستخدم رمز C/C++ ، فلا تنفيذ عمليات غير متوافقة مع ضغط GC. لقد قمنا بتحسين التحقق من JNI لتحديد بعض المشاكل المحتملة (كما هو موضح في JNI) التغييرات في المراجع المحلية في ICS)

أحد الجوانب التي يجب مراقبتها على وجه الخصوص هو استخدام Get...ArrayElements() وRelease...ArrayElements() الأخرى. وفي بيئات التشغيل التي تتضمن تجميعًا للبيانات عن طريق الخطأ بدون ضغط، ترجع الدوال Get...ArrayElements() عادةً إشارة إلى الذاكرة الفعلية التي تدعم كائن الصفيفة. إذا قمتَ بإجراء تغيير على إحدى عناصر الصفيفة التي تم إرجاعها، فسيتم تغيير كائن الصفيفة نفسه (والوسيطات إلى Release...ArrayElements() عادةً). ومع ذلك، إذا كان يتم استخدام تجميع البيانات المهملة، لذا قد تكون وظائف Get...ArrayElements() لإرجاع نسخة من الذكرى. إذا أسأت استخدام المرجع عند ضغط تجميع البيانات المهملة، قيد الاستخدام، وهذا قد يؤدي إلى تلف الذاكرة أو مشكلات أخرى. مثلاً:

  • إذا أجريت أي تغييرات على عناصر الصفيف المعروضة، فيجب عليك استدعاء دالة الرسم الدالة Release...ArrayElements() المناسبة عند الانتهاء، للتأكّد من نسخ التغييرات التي أجريتها بشكل صحيح إلى الصفحة الأساسية كائن الصفيفة.
  • عند تحرير عناصر صفيف الذاكرة، يجب عليك استخدام الأدوات المناسبة بناءً على التغييرات التي أجريتها:
    • إذا لم تقم بإجراء أي تغييرات على عناصر الصفيفة، فاستخدم وضع JNI_ABORT، الذي يحرر الذاكرة بدون نسخ التغييرات مرة أخرى إلى كائن الصفيفة الأساسية.
    • إذا أجريت تغييرات على الصفيف، ولم تكن بحاجة إلى المرجع أكثر، استخدم الرمز 0 (الذي يعدِّل كائن الصفيفة ويحرر عنصر الصفيفة) نسخة من الذكرى).
    • إذا قمتَ بإجراء تغييرات على الصفيف الذي تريد الالتزام به، وتريد للاحتفاظ بنسخة الصفيف، استخدم JNI_COMMIT (التي تعمل على تحديث كائن الصفيف الأساسي ويحتفظ بالنسخة).
  • عند الاتصال بـ Release...ArrayElements()، يُرجى إرجاعه مؤشر ما تم عرضه في الأصل بواسطة Get...ArrayElements(). بالنسبة على سبيل المثال، ليس من الآمن زيادة المؤشر الأصلي (للفحص عبر عناصر الصفيفة التي تم إرجاعها) ثم تمرير المؤشر المتزايد إلى Release...ArrayElements() يمكن أن يؤدي تمرير هذا المؤشر المعدَّل إلى الخطأ في الذاكرة التي سيتم تحريرها، مما يؤدي إلى تلف الذاكرة.

خطأ أثناء المعالجة

تطرح JNI، التابعة لـ ART، أخطاءً في عدد من الحالات التي لا يصادف فيها دالفيك. (مرة واحدة يمكنك الإصابة بالعديد من هذه الحالات عن طريق الاختبار باستخدام CheckJNI).

على سبيل المثال، إذا تم استدعاء RegisterNatives بطريقة غير موجود (ربما بسبب إزالة الطريقة بواسطة أداة مثل ProGuard)، يعرض ART الآن NoSuchMethodError بشكل صحيح:

08-12 17:09:41.082 13823 13823 E AndroidRuntime: FATAL EXCEPTION: main
08-12 17:09:41.082 13823 13823 E AndroidRuntime: java.lang.NoSuchMethodError:
    no static or non-static method
    "Lcom/foo/Bar;.native_frob(Ljava/lang/String;)I"
08-12 17:09:41.082 13823 13823 E AndroidRuntime:
    at java.lang.Runtime.nativeLoad(Native Method)
08-12 17:09:41.082 13823 13823 E AndroidRuntime:
    at java.lang.Runtime.doLoad(Runtime.java:421)
08-12 17:09:41.082 13823 13823 E AndroidRuntime:
    at java.lang.Runtime.loadLibrary(Runtime.java:362)
08-12 17:09:41.082 13823 13823 E AndroidRuntime:
    at java.lang.System.loadLibrary(System.java:526)

يسجل ART أيضًا خطأً (مرئي في Logcat) في حال كان RegisterNatives واستدعيت بدون طرق:

W/art     ( 1234): JNI RegisterNativeMethods: attempt to register 0 native
methods for <classname>

بالإضافة إلى ذلك، دالات JNI GetFieldID() يرمي GetStaticFieldID() الآن NoSuchFieldError بشكل صحيح بدلاً من مجرد إرجاع قيمة فارغة. وبالمثل، فإن GetMethodID() و يرمي GetStaticMethodID() الآن NoSuchMethodError بشكل صحيح. وقد يؤدي ذلك إلى إخفاقات CheckJNI بسبب الاستثناءات غير المعالجة أو والاستثناءات التي يتم طرحها لمتصلي Java بالرموز البرمجية الأصلية. هذا يجعل من على وجه الخصوص اختبار التطبيقات المتوافقة مع ART في وضع CheckJNI.

يتوقع ART من مستخدمي طرق CallNonvirtual...Method() التابعة لـ JNI (مثل CallNonvirtualVoidMethod()) لاستخدام بيان الطريقة وليس كفئة فرعية، كما هو مطلوب بواسطة مواصفات JNI.

منع المشاكل في حجم الحزمة

كان لدى دالفيك حزم منفصلة للرمز الأصلي ورمز Java، مع استخدام Java افتراضي يبلغ حجم الحزمة 32 كيلوبايت وحجم حزمة أصلية تلقائيًا يبلغ 1 ميغابايت. تتمتع ART بـ ART للحصول على منطقة محلية أفضل. تتوفر عادةً حزمة Thread من ART يجب أن يكون حجمها مطابقًا تقريبًا لـ Dalvik. ومع ذلك، إذا تعيين أحجام المكدس، فقد تحتاج إلى إعادة النظر في تلك القيم للتطبيقات التي تعمل في ART.

  • في Java، مراجعة عمليات الاستدعاء إلى الدالة الإنشائية Thread التي تحدد تكديسًا صريحًا الحجم. على سبيل المثال، ستحتاج إلى زيادة الحجم في حال ظهور StackOverflowError.
  • في لغة C/C++ ، راجع استخدام pthread_attr_setstack() pthread_attr_setstacksize() لسلاسل المحادثات التي تشغِّل أيضًا رمز Java من خلال JNI. في ما يلي مثال على الخطأ الذي يتم تسجيله عند محاولة أحد التطبيقات استدعاء JNI AttachCurrentThread() عندما يكون حجم pthread صغيرًا جدًا:
    F/art: art/runtime/thread.cc:435]
        Attempt to attach a thread with a too-small stack (16384 bytes)

تغييرات نموذج العناصر

سمح Dalvik بشكل غير صحيح للفئات الفرعية بتجاوز طرق الحزمة الخاصة. يُصدر ART تحذيرًا في مثل هذه الحالات:

Before Android 4.1, method void com.foo.Bar.quux()
would have incorrectly overridden the package-private method in
com.quux.Quux

إذا كنت تنوي إلغاء طريقة الفئة في حزمة مختلفة، فوضح كطريقة public أو protected.

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

Class.getSuperclass() == java.lang.Object.class

بدلاً من المتابعة إلى أن تعرض الطريقة القيمة null.

يتلقى الخادم الوكيل InvocationHandler.invoke() الآن null في حال عدم توفّر وسيطات بدلاً من صفيف فارغ. تم توثيق هذا السلوك سابقًا ولكن لم يتم التعامل معها بشكل صحيح في دالفيك. تواجه الإصدارات السابقة من Mockito صعوبات في لذا، يُرجى استخدام إصدار Mockito المحدَّث عند الاختبار باستخدام ART.

إصلاح مشاكل تجميع AOT

يجب أن يعمل تجميع Java لـ ART's Ahead-Time (AOT) مع جميع لغات Java القياسية الرمز. يتم التجميع بواسطة ART أداة dex2oat إذا واجهت أي مشكلات تتعلق dex2oat أثناء التثبيت، يُرجى إعلامنا بذلك (راجِع الإبلاغ عن المشاكل) لنتمكّن من حلّها في أسرع وقت ممكن. قدر الإمكان. في ما يلي بعض المشاكل التي يجب أخذها في الاعتبار:

  • تُجري أداة ART أثناء التثبيت عملية تحقّق أكثر صرامة من رمز البايت عند التثبيت مقارنةً بـ Dalvik. من المفترض أن يكون الرمز الذي يتم إنتاجه من خلال أدوات الإصدار في Android جيدًا. ومع ذلك، قد لا تكون قد ينتج عن أدوات ما بعد المعالجة (خاصة الأدوات التي تؤدي إلى إخفاء مفاتيح فك التشفير) إنتاج الملفات غير الصالحة التي تحملها Dalvik ولكن تم رفضها من قِبل ART. كنا والعمل مع موردي الأدوات للعثور على مثل هذه المشكلات وإصلاحها. في كثير من الحالات، قد يكون باستخدام أحدث إصدارات الأدوات وإعادة إنشاء ملفات DEX لإصلاح هذه المشكلات.
  • تتضمن بعض المشاكل النموذجية التي يتم الإبلاغ عنها من خلال أداة التحقق من ART ما يلي:
    • مسار تحكّم غير صالح
    • غير متوازن monitorenter/monitorexit
    • حجم قائمة أنواع المَعلمات ذات الطول 0
  • بعض التطبيقات تعتمد على ملف ".odex" المثبَّت بتنسيق /system/framework أو /data/dalvik-cache أو في دليل الإخراج المحسَّن لـ DexClassLoader. هذه الملفات هي الآن ملفات ELF وليست نموذجًا موسعًا من ملفات DEX. بينما يحاول ART لاتّباع قواعد التسمية والقفل نفسها التي يتّبعها Dalvik، يجب ألّا تعتمد بتنسيق الملف؛ فإن التنسيق عرضة للتغيير بدون إشعار.

    ملاحظة: في Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) أعلى، دليل الإخراج المحسن DexClassLoader تم إيقافه نهائيًا. لمزيد من المعلومات، راجع وثائق DexClassLoader() الدالة الإنشائية.

الإبلاغ عن المشاكل

في حال مواجهة أي مشاكل لا تتعلق بمشاكل JNI التطبيق، يُرجى الإبلاغ عنها عن طريق "أداة تتبُّع المشاكل" الخاصة بمشروع Android Open المصدر على الرابط https://code.google.com/p/android/issues/list. تضمين "adb bugreport" ورابط إلى التطبيق في Google "متجر Play" إن توفّر إذا كان ذلك ممكنًا، يمكنك إرفاق حزمة APK تعيد إنتاجها. المشكلة. يُرجى العلم أنّ المشاكل (بما في ذلك المرفقات) تظهر بشكل علني. مرئية.