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