الإصدار:
Android 11 (المستوى 30 لواجهة برمجة التطبيقات) - Thermal API
Android 12 (المستوى 31 لواجهة برمجة التطبيقات) - واجهة برمجة التطبيقات NDK
(الإصدار التجريبي) Android 15 (الإصدار الأول من الإصدار التجريبي) - getThermalHeadroomThresholds()
يعتمد الأداء المحتمل لتطبيقك على الحالة الحرارية للجهاز، والتي يمكن أن تختلف استنادًا إلى خصائص مثل الطقس وآخر استخدام وتصميم الجهاز الحراري. لا يمكن للأجهزة الحفاظ على مستوى مرتفع من الأداء إلا لفترة محدودة قبل أن يتم خفض سرعة المعالج بسبب ارتفاع درجة الحرارة. يجب أن يكون أحد أهداف التنفيذ الرئيسية هو تحقيق أهداف الأداء بدون تجاوز الحدود الحرارية. تتيح واجهة برمجة التطبيقات Thermal API إجراء ذلك بدون الحاجة إلى إجراء تحسينات خاصة بالأجهزة. بالإضافة إلى ذلك، عند تصحيح أخطاء الأداء، من المهم معرفة ما إذا كانت الحالة الحرارية لجهازك تحدّ من الأداء.
تحتوي عادةً محرّكات الألعاب على مَعلمات أداء وقت التشغيل التي يمكنها تعديل ملفه الشخصي المهام التي يفرضها المحرّك على الجهاز. على سبيل المثال، يمكن لهذه المَعلمات ضبط عدد سلاسل المهام العاملة، وارتباط سلاسل المهام العاملة بالنواة الكبيرة والصغيرة، وخيارات دقة وحدة معالجة الرسومات، ودرجات دقة إطار الذاكرة. في Unity Engine، يمكن لمطوّري الألعاب تعديل حجم العمل من خلال تغيير إعدادات الجودة باستخدام مكوّن Adaptive Performance الإضافي. بالنسبة إلى Unreal Engine، استخدِم إعدادات التوسّع لتعديل مستويات الجودة ديناميكيًا.
عندما يقترب الجهاز من حالة حرارية غير آمنة، يمكن أن تتجنب لعبتك البطء من خلال تقليل حجم المعالجة من خلال هذه المَعلمات. لتجنُّب التباطؤ، عليك تتبُّع الحالة الحرارية للجهاز وتعديل حجم معالجة محرك اللعبة بشكل استباقي. بعد ارتفاع درجة حرارة الجهاز، يجب أن ينخفض حجم العمل إلى ما دون مستوى الأداء المستدام لتبديد الحرارة. بعد أن ينخفض الحد الأقصى المسموح به للحرارة إلى مستويات أكثر أمانًا، يمكن أن تزيد اللعبة إعدادات الجودة مرة أخرى، ولكن احرص على العثور على مستوى جودة مستدام لوقت اللعب الأمثل.
يمكنك مراقبة الحالة الحرارية للجهاز من خلال الاستعلام عن الأسلوب
getThermalHeadroom
. وتتنبأ هذه الطريقة بالمدة التي يمكن للجهاز خلالها الحفاظ على
مستوى الأداء الحالي بدون ارتفاع درجة حرارته. إذا كان الوقت أقل من المدة
اللازمة لتشغيل حجم العمل، من المفترض أن تقلّل لعبتك من حجم العمل إلى
مستوى مستدام. على سبيل المثال، يمكن أن تنتقل اللعبة إلى نوى أصغر أو تخفض
عدد اللقطات في الثانية أو تخفض الدقّة.
![مرحلة ما قبل الدمج لواجهة برمجة التطبيقات ADPF Thermal API](https://developer.android.google.cn/static/games/optimize/adpf/images/adpf_thermal_pre-integration.png?authuser=4&hl=ar)
![مرحلة ما بعد الدمج لواجهة برمجة التطبيقات ADPF Thermal API](https://developer.android.google.cn/static/games/optimize/adpf/images/adpf_thermal_post-integration.png?authuser=4&hl=ar)
الحصول على تطبيق 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(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) وواجهة برمجة تطبيقات Java (من خلال JNI)، اطّلِع على قسم دمج واجهة برمجة التطبيقات Thermal API في قسم Adaptability codelab.
إرشادات هامش الحرارة
يمكنك مراقبة الحالة الحرارية للجهاز من خلال الاستعلام عن الأسلوب
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.
}
}
}
المخطّط: