1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "HardwarePropertiesManagerService-JNI"
18 
19 #include <aidl/android/hardware/thermal/IThermal.h>
20 #include <android/binder_manager.h>
21 #include <android/hardware/thermal/1.0/IThermal.h>
22 #include <math.h>
23 #include <nativehelper/JNIHelp.h>
24 #include <utils/Log.h>
25 #include <utils/String8.h>
26 
27 #include "core_jni_helpers.h"
28 #include "jni.h"
29 
30 namespace android {
31 
32 using ::aidl::android::hardware::thermal::CoolingDevice;
33 using ::aidl::android::hardware::thermal::IThermal;
34 using ::aidl::android::hardware::thermal::Temperature;
35 using ::aidl::android::hardware::thermal::TemperatureThreshold;
36 using ::aidl::android::hardware::thermal::TemperatureType;
37 using ::aidl::android::hardware::thermal::ThrottlingSeverity;
38 using android::hidl::base::V1_0::IBase;
39 using hardware::hidl_death_recipient;
40 using hardware::hidl_vec;
41 using hardware::thermal::V1_0::ThermalStatus;
42 using hardware::thermal::V1_0::ThermalStatusCode;
43 template<typename T>
44 using Return = hardware::Return<T>;
45 
46 // ---------------------------------------------------------------------------
47 
48 // These values must be kept in sync with the temperature source constants in
49 // HardwarePropertiesManager.java
50 enum {
51     TEMPERATURE_CURRENT = 0,
52     TEMPERATURE_THROTTLING = 1,
53     TEMPERATURE_SHUTDOWN = 2,
54     TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3
55 };
56 
57 static struct {
58     jclass clazz;
59     jmethodID initMethod;
60 } gCpuUsageInfoClassInfo;
61 
62 jfloat gUndefinedTemperature;
63 
64 static void getThermalHalLocked();
65 static std::mutex gThermalHalMutex;
66 static sp<hardware::thermal::V1_0::IThermal> gThermalHidlHal = nullptr;
67 static std::shared_ptr<IThermal> gThermalAidlHal = nullptr;
68 
69 struct ThermalHidlHalDeathRecipient : virtual public hidl_death_recipient {
70     // hidl_death_recipient interface
serviceDiedandroid::ThermalHidlHalDeathRecipient71     virtual void serviceDied(uint64_t cookie, const wp<IBase> &who) override {
72         std::lock_guard<std::mutex> lock(gThermalHalMutex);
73         ALOGE("Thermal HAL just died");
74         gThermalHidlHal = nullptr;
75         getThermalHalLocked();
76     }
77 };
78 
onThermalAidlBinderDied(void * cookie)79 static void onThermalAidlBinderDied(void *cookie) {
80     std::lock_guard<std::mutex> lock(gThermalHalMutex);
81     ALOGE("Thermal AIDL HAL just died");
82     gThermalAidlHal = nullptr;
83     getThermalHalLocked();
84 }
85 
86 sp<ThermalHidlHalDeathRecipient> gThermalHidlHalDeathRecipient = nullptr;
87 ndk::ScopedAIBinder_DeathRecipient gThermalAidlDeathRecipient;
88 
89 // ----------------------------------------------------------------------------
90 
finalizeTemperature(float temperature)91 float finalizeTemperature(float temperature) {
92     return isnan(temperature) ? gUndefinedTemperature : temperature;
93 }
94 
95 // The caller must be holding gThermalHalMutex.
getThermalHalLocked()96 static void getThermalHalLocked() {
97     if (gThermalAidlHal || gThermalHidlHal) {
98         return;
99     }
100     const std::string thermalInstanceName = std::string(IThermal::descriptor) + "/default";
101     if (AServiceManager_isDeclared(thermalInstanceName.c_str())) {
102         auto binder = AServiceManager_waitForService(thermalInstanceName.c_str());
103         auto thermalAidlService = IThermal::fromBinder(ndk::SpAIBinder(binder));
104         if (thermalAidlService) {
105             gThermalAidlHal = thermalAidlService;
106             if (gThermalAidlDeathRecipient.get() == nullptr) {
107                 gThermalAidlDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
108                         AIBinder_DeathRecipient_new(onThermalAidlBinderDied));
109             }
110             auto linked = AIBinder_linkToDeath(thermalAidlService->asBinder().get(),
111                                                gThermalAidlDeathRecipient.get(), nullptr);
112             if (linked != STATUS_OK) {
113                 ALOGW("Failed to link to death (AIDL): %d", linked);
114                 gThermalAidlHal = nullptr;
115             }
116         } else {
117             ALOGE("Unable to get Thermal AIDL service");
118         }
119         return;
120     }
121 
122     ALOGI("Thermal AIDL service is not declared, trying HIDL");
123     gThermalHidlHal = hardware::thermal::V1_0::IThermal::getService();
124 
125     if (gThermalHidlHal == nullptr) {
126         ALOGE("Unable to get Thermal service.");
127     } else {
128         if (gThermalHidlHalDeathRecipient == nullptr) {
129             gThermalHidlHalDeathRecipient = new ThermalHidlHalDeathRecipient();
130         }
131         hardware::Return<bool> linked =
132                 gThermalHidlHal->linkToDeath(gThermalHidlHalDeathRecipient, 0x451F /* cookie */);
133         if (!linked.isOk()) {
134             ALOGE("Transaction error in linking to ThermalHAL death: %s",
135                   linked.description().c_str());
136             gThermalHidlHal = nullptr;
137         } else if (!linked) {
138             ALOGW("Unable to link to ThermalHal death notifications");
139             gThermalHidlHal = nullptr;
140         } else {
141             ALOGD("Link to death notification successful");
142         }
143     }
144 }
145 
nativeInit(JNIEnv * env,jobject obj)146 static void nativeInit(JNIEnv* env, jobject obj) {
147     std::lock_guard<std::mutex> lock(gThermalHalMutex);
148     getThermalHalLocked();
149 }
150 
getFanSpeedsAidl(JNIEnv * env)151 static jfloatArray getFanSpeedsAidl(JNIEnv *env) {
152     std::vector<CoolingDevice> list;
153     auto status = gThermalAidlHal->getCoolingDevices(&list);
154     if (!status.isOk()) {
155         ALOGE("getFanSpeeds failed status: %s", status.getMessage());
156         return env->NewFloatArray(0);
157     }
158     float values[list.size()];
159     for (size_t i = 0; i < list.size(); ++i) {
160         values[i] = list[i].value;
161     }
162     jfloatArray fanSpeeds = env->NewFloatArray(list.size());
163     env->SetFloatArrayRegion(fanSpeeds, 0, list.size(), values);
164     return fanSpeeds;
165 }
166 
getFanSpeedsHidl(JNIEnv * env)167 static jfloatArray getFanSpeedsHidl(JNIEnv *env) {
168     hidl_vec<hardware::thermal::V1_0::CoolingDevice> list;
169     Return<void> ret = gThermalHidlHal->getCoolingDevices(
170             [&list](ThermalStatus status,
171                     hidl_vec<hardware::thermal::V1_0::CoolingDevice> devices) {
172                 if (status.code == ThermalStatusCode::SUCCESS) {
173                     list = std::move(devices);
174                 } else {
175                     ALOGE("Couldn't get fan speeds because of HAL error: %s",
176                           status.debugMessage.c_str());
177                 }
178             });
179 
180     if (!ret.isOk()) {
181         ALOGE("getFanSpeeds failed status: %s", ret.description().c_str());
182         return env->NewFloatArray(0);
183     }
184     float values[list.size()];
185     for (size_t i = 0; i < list.size(); ++i) {
186         values[i] = list[i].currentValue;
187     }
188     jfloatArray fanSpeeds = env->NewFloatArray(list.size());
189     env->SetFloatArrayRegion(fanSpeeds, 0, list.size(), values);
190     return fanSpeeds;
191 }
192 
nativeGetFanSpeeds(JNIEnv * env,jclass)193 static jfloatArray nativeGetFanSpeeds(JNIEnv *env, jclass /* clazz */) {
194     std::lock_guard<std::mutex> lock(gThermalHalMutex);
195     getThermalHalLocked();
196     if (!gThermalHidlHal && !gThermalAidlHal) {
197         ALOGE("Couldn't get fan speeds because of HAL error.");
198         return env->NewFloatArray(0);
199     }
200     if (gThermalAidlHal) {
201         return getFanSpeedsAidl(env);
202     }
203     return getFanSpeedsHidl(env);
204 }
205 
getDeviceTemperaturesAidl(JNIEnv * env,int type,int source)206 static jfloatArray getDeviceTemperaturesAidl(JNIEnv *env, int type, int source) {
207     jfloat *values;
208     size_t length = 0;
209     if (source == TEMPERATURE_CURRENT) {
210         std::vector<Temperature> list;
211         auto status =
212                 gThermalAidlHal->getTemperaturesWithType(static_cast<TemperatureType>(type), &list);
213 
214         if (!status.isOk()) {
215             ALOGE("getDeviceTemperatures failed status: %s", status.getMessage());
216             return env->NewFloatArray(0);
217         }
218         values = new jfloat[list.size()];
219         for (const auto &temp : list) {
220             if (static_cast<int>(temp.type) == type) {
221                 values[length++] = finalizeTemperature(temp.value);
222             }
223         }
224     } else if (source == TEMPERATURE_THROTTLING_BELOW_VR_MIN) {
225         values = new jfloat[1];
226         values[length++] = gUndefinedTemperature;
227     } else {
228         std::vector<TemperatureThreshold> list;
229         auto status =
230                 gThermalAidlHal->getTemperatureThresholdsWithType(static_cast<TemperatureType>(
231                                                                           type),
232                                                                   &list);
233 
234         if (!status.isOk()) {
235             ALOGE("getDeviceTemperatures failed status: %s", status.getMessage());
236             return env->NewFloatArray(0);
237         }
238         values = new jfloat[list.size()];
239         for (auto &t : list) {
240             if (static_cast<int>(t.type) == type) {
241                 switch (source) {
242                     case TEMPERATURE_THROTTLING:
243                         values[length++] =
244                                 finalizeTemperature(t.hotThrottlingThresholds[static_cast<int>(
245                                         ThrottlingSeverity::SEVERE)]);
246                         break;
247                     case TEMPERATURE_SHUTDOWN:
248                         values[length++] =
249                                 finalizeTemperature(t.hotThrottlingThresholds[static_cast<int>(
250                                         ThrottlingSeverity::SHUTDOWN)]);
251                         break;
252                 }
253             }
254         }
255     }
256     jfloatArray deviceTemps = env->NewFloatArray(length);
257     env->SetFloatArrayRegion(deviceTemps, 0, length, values);
258     return deviceTemps;
259 }
260 
getDeviceTemperaturesHidl(JNIEnv * env,int type,int source)261 static jfloatArray getDeviceTemperaturesHidl(JNIEnv *env, int type, int source) {
262     hidl_vec<hardware::thermal::V1_0::Temperature> list;
263     Return<void> ret = gThermalHidlHal->getTemperatures(
264             [&list](ThermalStatus status,
265                     hidl_vec<hardware::thermal::V1_0::Temperature> temperatures) {
266                 if (status.code == ThermalStatusCode::SUCCESS) {
267                     list = std::move(temperatures);
268                 } else {
269                     ALOGE("Couldn't get temperatures because of HAL error: %s",
270                           status.debugMessage.c_str());
271                 }
272             });
273 
274     if (!ret.isOk()) {
275         ALOGE("getDeviceTemperatures failed status: %s", ret.description().c_str());
276         return env->NewFloatArray(0);
277     }
278     float values[list.size()];
279     size_t length = 0;
280     for (size_t i = 0; i < list.size(); ++i) {
281         if (static_cast<int>(list[i].type) == type) {
282             switch (source) {
283                 case TEMPERATURE_CURRENT:
284                     values[length++] = finalizeTemperature(list[i].currentValue);
285                     break;
286                 case TEMPERATURE_THROTTLING:
287                     values[length++] = finalizeTemperature(list[i].throttlingThreshold);
288                     break;
289                 case TEMPERATURE_SHUTDOWN:
290                     values[length++] = finalizeTemperature(list[i].shutdownThreshold);
291                     break;
292                 case TEMPERATURE_THROTTLING_BELOW_VR_MIN:
293                     values[length++] = finalizeTemperature(list[i].vrThrottlingThreshold);
294                     break;
295             }
296         }
297     }
298     jfloatArray deviceTemps = env->NewFloatArray(length);
299     env->SetFloatArrayRegion(deviceTemps, 0, length, values);
300     return deviceTemps;
301 }
302 
nativeGetDeviceTemperatures(JNIEnv * env,jclass,int type,int source)303 static jfloatArray nativeGetDeviceTemperatures(JNIEnv *env, jclass /* clazz */, int type,
304                                                int source) {
305     std::lock_guard<std::mutex> lock(gThermalHalMutex);
306     getThermalHalLocked();
307     if (!gThermalHidlHal && !gThermalAidlHal) {
308         ALOGE("Couldn't get device temperatures because of HAL error.");
309         return env->NewFloatArray(0);
310     }
311     if (gThermalAidlHal) {
312         return getDeviceTemperaturesAidl(env, type, source);
313     }
314     return getDeviceTemperaturesHidl(env, type, source);
315 }
316 
nativeGetCpuUsages(JNIEnv * env,jclass)317 static jobjectArray nativeGetCpuUsages(JNIEnv *env, jclass /* clazz */) {
318     std::lock_guard<std::mutex> lock(gThermalHalMutex);
319     getThermalHalLocked();
320     if (gThermalAidlHal) {
321         ALOGW("getCpuUsages is not supported");
322         return env->NewObjectArray(0, gCpuUsageInfoClassInfo.clazz, nullptr);
323     }
324     if (gThermalHidlHal == nullptr || !gCpuUsageInfoClassInfo.initMethod) {
325         ALOGE("Couldn't get CPU usages because of HAL error.");
326         return env->NewObjectArray(0, gCpuUsageInfoClassInfo.clazz, nullptr);
327     }
328     hidl_vec<hardware::thermal::V1_0::CpuUsage> list;
329     Return<void> ret = gThermalHidlHal->getCpuUsages(
330             [&list](ThermalStatus status, hidl_vec<hardware::thermal::V1_0::CpuUsage> cpuUsages) {
331                 if (status.code == ThermalStatusCode::SUCCESS) {
332                     list = std::move(cpuUsages);
333                 } else {
334                     ALOGE("Couldn't get CPU usages because of HAL error: %s",
335                           status.debugMessage.c_str());
336                 }
337             });
338 
339     if (!ret.isOk()) {
340         ALOGE("getCpuUsages failed status: %s", ret.description().c_str());
341         return env->NewObjectArray(0, gCpuUsageInfoClassInfo.clazz, nullptr);
342     }
343 
344     jobjectArray cpuUsages = env->NewObjectArray(list.size(), gCpuUsageInfoClassInfo.clazz,
345                                                  nullptr);
346     for (size_t i = 0; i < list.size(); ++i) {
347         if (list[i].isOnline) {
348             jobject cpuUsage = env->NewObject(gCpuUsageInfoClassInfo.clazz,
349                                               gCpuUsageInfoClassInfo.initMethod,
350                                               list[i].active,
351                                               list[i].total);
352             env->SetObjectArrayElement(cpuUsages, i, cpuUsage);
353         }
354     }
355     return cpuUsages;
356 }
357 
358 // ----------------------------------------------------------------------------
359 
360 static const JNINativeMethod gHardwarePropertiesManagerServiceMethods[] = {
361     /* name, signature, funcPtr */
362     { "nativeInit", "()V",
363             (void*) nativeInit },
364     { "nativeGetFanSpeeds", "()[F",
365             (void*) nativeGetFanSpeeds },
366     { "nativeGetDeviceTemperatures", "(II)[F",
367             (void*) nativeGetDeviceTemperatures },
368     { "nativeGetCpuUsages", "()[Landroid/os/CpuUsageInfo;",
369             (void*) nativeGetCpuUsages }
370 };
371 
register_android_server_HardwarePropertiesManagerService(JNIEnv * env)372 int register_android_server_HardwarePropertiesManagerService(JNIEnv* env) {
373     int res = jniRegisterNativeMethods(env, "com/android/server/HardwarePropertiesManagerService",
374                                        gHardwarePropertiesManagerServiceMethods,
375                                        NELEM(gHardwarePropertiesManagerServiceMethods));
376     jclass clazz = env->FindClass("android/os/CpuUsageInfo");
377     gCpuUsageInfoClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
378     gCpuUsageInfoClassInfo.initMethod = GetMethodIDOrDie(env, gCpuUsageInfoClassInfo.clazz,
379                                                          "<init>", "(JJ)V");
380 
381     clazz = env->FindClass("android/os/HardwarePropertiesManager");
382     jfieldID undefined_temperature_field = GetStaticFieldIDOrDie(env, clazz,
383                                                                  "UNDEFINED_TEMPERATURE", "F");
384     gUndefinedTemperature = env->GetStaticFloatField(clazz, undefined_temperature_field);
385 
386     return res;
387 }
388 
389 } /* namespace android */
390