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