تاريخ الإصدار:
Android 11 (المستوى 30) - واجهة برمجة التطبيقات الحرارية
Android 12 (المستوى 31) - NDK API
(معاينة) Android 15 (DP1) - getThermalHeadroomThresholds()
يعتمد الأداء المحتمَل لتطبيقك على الحالة الحرارية للجهاز، والتي يمكن أن تختلف استنادًا إلى خصائص مثل الطقس والاستخدام الحديث والتصميم الحراري للجهاز. يمكن للأجهزة الحفاظ على مستوى عالٍ من الأداء فقط لفترة محدودة من الوقت قبل أن يتم تقييدها حراريًا. يجب أن يكون الهدف الرئيسي من عملية التنفيذ هو تحقيق أهداف الأداء بدون تجاوز القيود الحرارية. تتيح واجهة برمجة التطبيقات الحرارية إنجاز المهام بدون الحاجة إلى تحسينات خاصة بالجهاز. علاوة على ذلك، عند تصحيح أخطاء الأداء، من المهم معرفة ما إذا كانت الحالة الحرارية لجهازك تحدّ من الأداء. بالإضافة إلى ذلك، عند تصحيح مشاكل الأداء، من المهم معرفة ما إذا كانت الحالة الحرارية لجهازك تحدّ من الأداء.
عادةً ما تحتوي محركات الألعاب على معلمات أداء في وقت التشغيل يمكنها ضبط عبء العمل الذي يضعه المحرك على الجهاز. على سبيل المثال، يمكن أن تُعيِّن هذه المعلَمات عدد سلاسل العمليات، والتقارب مع خيوط العامل للنوى الكبيرة والصغيرة، وخيارات دقة وحدة معالجة الرسومات، ودرجات دقة المخزن المؤقت للإطارات. في Unity Engine، يمكن لمطوّري الألعاب تعديل أعباء العمل من خلال تغيير إعدادات الجودة باستخدام المكوّن الإضافي Adaptive Performance. بالنسبة إلى Unreal Engine، استخدِم إعدادات قابلية التوسّع لضبط مستويات الجودة ديناميكيًا.
عندما يقترب جهاز من الحالة الحرارية غير الآمنة، يمكن أن تتجنّب لعبتك التقييد من خلال تقليل أعباء العمل باستخدام هذه المَعلمات. ولتجنّب هذه القيود، يجب مراقبة الحالة الحرارية للجهاز وضبط عبء عمل محرّك اللعبة بشكل استباقي. بمجرد ارتفاع درجة حرارة الجهاز، يجب أن ينخفض عبء العمل إلى ما دون مستوى الأداء المستدام لتبديد الحرارة. بعد انخفاض هامش الحرارة إلى مستويات أكثر أمانًا، يمكن للّعبة زيادة إعدادات الجودة مرة أخرى، ولكن مع الحرص على العثور على مستوى جودة مستدام لضمان وقت اللعب الأمثل.
يمكنك تتبّع الحالة الحرارية للجهاز من خلال إجراء استطلاع في الطريقة
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()
.
مثال على الإرشادات:
- تحقَّق من أنّ واجهة برمجة التطبيقات Thermal API متاحة. يتحقّق
isAPISupported()
من قيمة الاستدعاء الأول إلىgetThermalHeadroom
للتأكّد من أنّها ليست 0 أو NaN، ويتخطّى استخدام واجهة برمجة التطبيقات إذا كانت القيمة الأولى 0 أو NaN. - وإذا كان
getCurrentThermalStatus()
يعرض قيمة بخلافTHERMAL_STATUS_NONE
، سيتم تقييد الجهاز حراريًا. - إذا استمر ظهور السمة
getCurrentThermalStatus()
في عرضTHERMAL_STATUS_NONE
، لا يعني ذلك بالضرورة أنّ الجهاز لا يتم تقييده حراريًا. قد يعني ذلك أنّ اللغةgetCurrentThermalStatus()
غير متوافقة مع الجهاز. تحقَّق من القيمة المعروضةgetThermalHeadroom()
للتأكّد من حالة الجهاز. - إذا كان
getThermalHeadroom()
يعرض قيمة أكبر من 1.0، يمكن أن تكون الحالةTHERMAL_STATUS_SEVERE
أو أعلى، ويمكن تقليل أعباء العمل على الفور وتقليل أعباء العمل حتى تعرضgetThermalHeadroom()
قيمة أقل. - إذا كان
getThermalHeadroom()
يعرض القيمة 0.95، يمكن أن تكون الحالةTHERMAL_STATUS_MODERATE
أو أعلى، يمكنك تقليل أعباء العمل على الفور وإبقاء الانتباه لمنع القراءة الأعلى - إذا كان
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.
}
}
}
الرسم التخطيطي: