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

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

Android 11 (المستوى 30) - واجهة برمجة التطبيقات الحرارية

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

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

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

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

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

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

مرحلة ما قبل الدمج مع ADPF Thermal API
الشكل 1. هامش الحرارة الحراري بدون رصد getThermalHeadroom بشكل نشط
مرحلة ما بعد الدمج مع ADPF Thermal API
الشكل 2. نظام الحرارة الحراري مع ميزة المراقبة النشطة "getThermalHeadroom"

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

لاستخدام واجهة برمجة التطبيقات الحرارية، يجب أولاً الحصول على "مدير الحرارة"

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 API من خلال JNI واحتفظت بمرجع ما، تذكر حذف المرجع.

C++‎

AThermal_releaseManager(thermal_manager);

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

إرشادات هامش الحرارة

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

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

القيود المفروضة على الجهاز في 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.مثال على أسلوب إرشادي لتحديد دعم واجهة برمجة التطبيقات الحرارية على الأجهزة القديمة