واجهة برمجة تطبيقات حرارية

تاريخ الإصدار:

Android 11 (المستوى 30) - Thermal API

Android 12 (المستوى 31) - NDK API

(معاينة) Android 15 (DP1) - getThermalHeadroomThresholds()

يعتمد الأداء المحتمل لتطبيقك على الحالة الحرارية والذي قد يختلف بناءً على خصائص مثل الطقس والاستخدام الأخير والتصميم الحراري للجهاز. يمكن للأجهزة الحفاظ على مستوى عالٍ من لفترة محدودة من الوقت قبل أن يتم تقييدها حراريًا. المفتاح يجب أن يكون الهدف من التنفيذ هو تحقيق أهداف الأداء بدون وتجاوز القيود الحرارية. تتيح واجهة برمجة التطبيقات Thermal API إمكانية استخدامها بدون الحاجة إلى لإجراء تحسينات خاصة بالجهاز. علاوةً على ذلك، عند تصحيح أخطاء الأداء فمعرفة ما إذا كانت الحالة الحرارية للجهاز تحدّ من الأداء التحليل.

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

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

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

مرحلة ما قبل الدمج مع واجهة برمجة التطبيقات ADPF Thermal API
الشكل 1. "السماعة الحرارية" بدون الرصد الفعّال لـ GetThermalHeadroom
عملية ما بعد دمج ADPF Thermal API
الشكل 2. السماعة الحرارية مع رصد نشاط "getThermalHeadroom"

الحصول على مدير الحرارة

لاستخدام Thermal API، عليك أولاً الحصول على تطبيق Thermal Manager

C++‎

AThermalManager* thermal_manager = AThermal_acquireManager();

Java

PowerManager powerManager = (PowerManager)this.getSystemService(Context.POWER_SERVICE);

توقَّع أن تكون المساحة المستخدَمة للارتفاع بمقدار x ثانية لتحقيق مزيد من التحكّم.

يمكنك أن تطلب من النظام توقُّع درجة الحرارة قبل الحدث بـ x ثانية من خلال عبء العمل الحالي. ويمنحك هذا تحكمًا أكثر دقةً والمزيد من الوقت من خلال تقليل عبء العمل لمنع التقييد الحراري.

تتراوح النتيجة من 0.0f (بدون تقييد، THERMAL_STATUS_NONE) إلى 1.0f. (تقييد شديد، THERMAL_STATUS_SEVERE). إذا كانت لديك مستويات مختلفة لجودة الرسومات في ألعابك، يمكنك اتّباع إرشادات هامش الحرارة

C++‎

float thermal_headroom = AThermal_getThermalHeadroom(10);
ALOGI("ThermalHeadroom in 10 sec: %f", thermal_headroom);

Java

float thermalHeadroom = powerManager.getThermalHeadroom(10);
Log.d("ADPF", "ThermalHeadroom in 10 sec: " + thermalHeadroom);

أو الاعتماد على الحالة الحرارية للحصول على توضيح

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

C++‎

AThermalStatus thermal_status = AThermal_getCurrentThermalStatus(thermal_manager);
ALOGI("ThermalStatus is: %d", thermal_status);

Java

int thermalStatus = powerManager.getCurrentThermalStatus();
Log.d("ADPF", "ThermalStatus is: " + thermalStatus);

يمكنك تلقّي إشعارات عند تغيُّر الحالة الحرارية.

يمكنك أيضًا تجنُّب إجراء استطلاعات على thermalHeadroom حتى وصول thermalStatus. مستوى معيّن (مثل: THERMAL_STATUS_LIGHT). ولإجراء ذلك، يمكنك تسجيل معاودة اتصال لكي يُعلمك النظام متى حالة تغيرت حالتها.

C++‎

int result = AThermal_registerThermalStatusListener(thermal_manager, callback);
if ( result != 0 ) {
  // failed, check whether you have previously registered callback that
  // hasn’t been unregistered
}

Java

// PowerManager.OnThermalStatusChangedListener is an interface, thus you can
// also define a class that implements the methods
PowerManager.OnThermalStatusChangedListener listener = new
  PowerManager.OnThermalStatusChangedListener() {
    @Override
    public void onThermalStatusChanged(int status) {
        Log.d("ADPF", "ThermalStatus changed: " + status);
        // check the status and flip the flag to start/stop pooling when
        // applicable
    }
};
powerManager.addThermalStatusListener(listener);

تذكر إزالة المستمع عند الانتهاء

C++‎

int result = AThermal_unregisterThermalStatusListener(thermal_manager, callback);
if ( result != 0 ) {
  // failed, check whether the callback has been registered previously
}

Java

powerManager.removeThermalStatusListener(listener);

تنظيف

بعد الانتهاء، عليك حذف حساب thermal_manager الذي حصلت عليه. إذا كنت تستخدم Java، فقد يصبح مرجع PowerManager غير مرغوب فيه تلقائيًا جمعتها لك. ولكن إذا كنت تستخدم واجهة برمجة تطبيقات Java من خلال JNI وكان لديك احتفظت بمرجع، تذكر تنظيف المرجع!

C++‎

AThermal_releaseManager(thermal_manager);

للحصول على دليل كامل حول كيفية تنفيذ Thermal API على لعبة C++ أصلية باستخدام كل من واجهة برمجة تطبيقات C++ (NDK API) وJava API (من خلال JNI)، اطلع على دمج قسم Thermal API ضمن الدرس التطبيقي حول الترميز Adaptability .

إرشادات الارتفاع الحراري

يمكنك مراقبة الحالة الحرارية للجهاز من خلال استطلاع getThermalHeadroom . تتنبأ هذه الطريقة بالمدة التي يمكن أن يحافظ فيها الجهاز على مستوى الأداء قبل الوصول إلى THERMAL_STATUS_SEVERE. على سبيل المثال، إذا عرضت getThermalHeadroom(30) القيمة 0.8، فإنها تشير إلى أنّها في 30. ثانية، ومن المتوقع أن يصل الارتفاع إلى 0.8، حيث توجد مسافة 0.2 من التقييد الشديد، أو 1.0. إذا كان الوقت أقل من المبلغ المطلوب من أعباء العمل، فمن المفترض أن تخفِّض لعبتك أعباء العمل إلى المستوى. على سبيل المثال، يمكن للعبة تقليل عدد اللقطات في الثانية أو تقليل الدقّة أو وتقليل عمل اتصال الشبكة.

الحالات الحرارية والمعنى

قيود الأجهزة في Thermal API

هناك بعض القيود المعروفة أو المتطلبات الإضافية لواجهة Thermal API، بسبب إلى تنفيذ واجهة برمجة التطبيقات الحرارية على الأجهزة القديمة. القيود وكيف لحلّها هي:

  • عدم طلب واجهة برمجة التطبيقات GetThermalHeadroom() بشكل متكرّر سيؤدي القيام بذلك إلى إلى واجهة برمجة التطبيقات التي تعرض NaN. يجب الاتصال به مرة واحدة في الثانية كحد أقصى.
  • إذا كانت القيمة الأولية لـ GetThermalHeadroom() هي NaN، لن تكون واجهة برمجة التطبيقات متوفّر على الجهاز
  • إذا كانت الدالة GetThermalHeadroom() تعرض قيمة عالية (مثل 0.85 أو أكثر) لا تزال تعرض GetCurrentThermalStatus() عملية إرجاع بقيمة THERMAL_STATUS_NONE، والحالة هي من المحتمل ألا يتم تحديثها. استخدام الأساليب الإرشادية لتقدير التقييد الحراري الصحيح أو استخدام getThermalHeadroom() بدون getCurrentThermalStatus().

مثال على الأساليب الإرشادية:

  1. تحقَّق من توافق واجهة برمجة التطبيقات Thermal API. يتحقق isAPISupported() من قيمة الاستدعاء الأول إلى getThermalHeadroom للتأكد من أنه ليس 0 أو NaN باستخدام واجهة برمجة التطبيقات إذا كانت القيمة الأولى هي 0 أو NaN.
  2. إذا كانت getCurrentThermalStatus() تُرجع قيمة أخرى غير THERMAL_STATUS_NONE، يتم تقييد الجهاز حراريًا.
  3. إذا استمر عرض getCurrentThermalStatus() في THERMAL_STATUS_NONE، سيتم هذا لا يعني بالضرورة أن الجهاز لا يتم تقييده حراريًا. يمكنه يعني أنّ getCurrentThermalStatus() غير متاح على الجهاز. تحقّق من القيمة المعروضة getThermalHeadroom() للتأكّد من حالة الجهاز.
  4. إذا كانت getThermalHeadroom() تعرض القيمة > 1.0، فإن الحالة يمكن تكون في الواقع THERMAL_STATUS_SEVERE أو أعلى، قلّل عبء العمل على الفور الحفاظ على عبء عمل أقل حتى يعرض getThermalHeadroom() قيمة أقل
  5. إذا عرضت getThermalHeadroom() القيمة 0.95، فإن الحالة يمكن أن تكون في الواقع THERMAL_STATUS_MODERATE أو أعلى، وعليك تقليل عبء العمل على الفور. ومواصلة الانتباه لمنع القراءة الأعلى
  6. إذا عرضت getThermalHeadroom() القيمة 0.85، فإن الحالة يمكن أن في الواقع THERMAL_STATUS_LIGHT، يُرجى الانتباه والحدّ من عبء العمل إن أمكن

الكود الزائف:

  bool isAPISupported() {
    float first_value_of_thermal_headroom = getThermalHeadroom();
    if ( first_value_of_thermal_headroom == 0 ||
      first_value_of_thermal_headroom == NaN ) {
        // Checked the thermal Headroom API's initial return value
        // it is NaN or 0,so, return false (not supported)
        return false;
    }
    return true;
  }
  
  if (!isAPISupported()) {
    // Checked the thermal Headroom API's initial return value, it is NaN or 0
    // Don’t use the API
  } else {
      // Use thermalStatus API to check if it returns valid values.
      if (getCurrentThermalStatus() > THERMAL_STATUS_NONE) {
          // The device IS being thermally throttled
      } else {
      // The device is not being thermally throttled currently. However, it
      // could also be an indicator that the ThermalStatus API may not be
      // supported in the device.
      // Currently this API uses predefined threshold values for thermal status
      // mapping. In the future  you may be able to query this directly.
      float thermal_headroom = getThermalHeadroom();
      if ( thermal_headroom > 1.0) {
            // The device COULD be severely throttled.
      } else  if ( thermal_headroom > 0.95) {
            // The device COULD be moderately throttled.
      } else if ( thermal_headroom > 0.85) {
            // The device COULD be experiencing light throttling.
      }
    }
  }

مخطط:

مثال توجيهي بشأن ADPF
الشكل 3: مثال على Heuristic لتحديد توافق Thermal API على الأجهزة القديمة