Thermal API

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

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

‫Android 12 (المستوى 31 لواجهة برمجة التطبيقات) - واجهة برمجة التطبيقات NDK API

(إصدار تجريبي) Android 15 (الإصدار الأولي 1) - getThermalHeadroomThresholds()

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

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

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

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

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

الدمج المُسبَق لواجهة برمجة التطبيقات الحرارية ADPF
الشكل 1. المساحة الحرارية بدون مراقبة `getThermalHeadroom` بشكل نشط
ADPF Thermal API Post-Integration
الشكل 2. المساحة الحرارية مع المراقبة النشطة للطريقة `getThermalHeadroom`

الحصول على Thermal Manager

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

C++‎

AThermalManager* thermal_manager = AThermal_acquireManager();

Java

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

الاستعلام عن المساحة الحرارية

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

يتراوح الناتج بين 0.0f (بدون تقليل الأداء بسبب الحرارة، THERMAL_STATUS_NONE)

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

C++‎

float thermal_headroom = AThermal_getThermalHeadroom(0);
ALOGI("ThermalHeadroom: %f", thermal_headroom);

Java

float thermalHeadroom = powerManager.getThermalHeadroom(0);
Log.d("ADPF", "ThermalHeadroom: " + 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++ API (واجهة برمجة التطبيقات NDK API) وواجهة برمجة التطبيقات Java API (من خلال JNI)، يمكنك الاطّلاع على قسم دمج واجهة برمجة التطبيقات Thermal API في قسم Adaptability في الدرس التطبيقي حول الترميز.

إرشادات المساحة الحرارية

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

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

قيود واجهة برمجة التطبيقات Thermal API على الأجهزة

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

  • لا تطلب بيانات واجهة برمجة التطبيقات GetThermalHeadroom() بشكل متكرّر جدًا. إذا فعلت ذلك، ستعرض واجهة برمجة التطبيقات NaN. يجب ألا تطلب بياناتها أكثر من مرة واحدة كل 10 ثوانٍ.
  • تجنَّب طلب البيانات من سلاسل متعددة، لأنّه من الصعب ضمان تكرار طلب البيانات وقد يؤدي ذلك إلى أن تعرض واجهة برمجة التطبيقات 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.مثال على الإعدادات الإرشادية لتحديد مدى توافق واجهة برمجة التطبيقات Thermal API على الأجهزة القديمة