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 <nativehelper/JNIHelp.h>
20 #include "jni.h"
21
22 #include <math.h>
23 #include <stdlib.h>
24
25 #include <android/hardware/thermal/1.0/IThermal.h>
26 #include <utils/Log.h>
27 #include <utils/String8.h>
28
29 #include "core_jni_helpers.h"
30
31 namespace android {
32
33 using android::hidl::base::V1_0::IBase;
34 using hardware::hidl_death_recipient;
35 using hardware::hidl_vec;
36 using hardware::thermal::V1_0::CoolingDevice;
37 using hardware::thermal::V1_0::CpuUsage;
38 using hardware::thermal::V1_0::IThermal;
39 using hardware::thermal::V1_0::Temperature;
40 using hardware::thermal::V1_0::ThermalStatus;
41 using hardware::thermal::V1_0::ThermalStatusCode;
42 template<typename T>
43 using Return = hardware::Return<T>;
44
45 // ---------------------------------------------------------------------------
46
47 // These values must be kept in sync with the temperature source constants in
48 // HardwarePropertiesManager.java
49 enum {
50 TEMPERATURE_CURRENT = 0,
51 TEMPERATURE_THROTTLING = 1,
52 TEMPERATURE_SHUTDOWN = 2,
53 TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3
54 };
55
56 static struct {
57 jclass clazz;
58 jmethodID initMethod;
59 } gCpuUsageInfoClassInfo;
60
61 jfloat gUndefinedTemperature;
62
63 static void getThermalHalLocked();
64 static std::mutex gThermalHalMutex;
65 static sp<IThermal> gThermalHal = nullptr;
66
67 // struct ThermalHalDeathRecipient;
68 struct ThermalHalDeathRecipient : virtual public hidl_death_recipient {
69 // hidl_death_recipient interface
serviceDiedandroid::ThermalHalDeathRecipient70 virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override {
71 std::lock_guard<std::mutex> lock(gThermalHalMutex);
72 ALOGE("ThermalHAL just died");
73 gThermalHal = nullptr;
74 getThermalHalLocked();
75 }
76 };
77
78 sp<ThermalHalDeathRecipient> gThermalHalDeathRecipient = nullptr;
79
80 // ----------------------------------------------------------------------------
81
finalizeTemperature(float temperature)82 float finalizeTemperature(float temperature) {
83 return isnan(temperature) ? gUndefinedTemperature : temperature;
84 }
85
86 // The caller must be holding gThermalHalMutex.
getThermalHalLocked()87 static void getThermalHalLocked() {
88 if (gThermalHal != nullptr) {
89 return;
90 }
91
92 gThermalHal = IThermal::getService();
93
94 if (gThermalHal == nullptr) {
95 ALOGE("Unable to get Thermal service.");
96 } else {
97 if (gThermalHalDeathRecipient == nullptr) {
98 gThermalHalDeathRecipient = new ThermalHalDeathRecipient();
99 }
100 hardware::Return<bool> linked = gThermalHal->linkToDeath(
101 gThermalHalDeathRecipient, 0x451F /* cookie */);
102 if (!linked.isOk()) {
103 ALOGE("Transaction error in linking to ThermalHAL death: %s",
104 linked.description().c_str());
105 gThermalHal = nullptr;
106 } else if (!linked) {
107 ALOGW("Unable to link to ThermalHal death notifications");
108 gThermalHal = nullptr;
109 } else {
110 ALOGD("Link to death notification successful");
111 }
112 }
113 }
114
nativeInit(JNIEnv * env,jobject obj)115 static void nativeInit(JNIEnv* env, jobject obj) {
116 std::lock_guard<std::mutex> lock(gThermalHalMutex);
117 getThermalHalLocked();
118 }
119
nativeGetFanSpeeds(JNIEnv * env,jclass)120 static jfloatArray nativeGetFanSpeeds(JNIEnv *env, jclass /* clazz */) {
121 std::lock_guard<std::mutex> lock(gThermalHalMutex);
122 getThermalHalLocked();
123 if (gThermalHal == nullptr) {
124 ALOGE("Couldn't get fan speeds because of HAL error.");
125 return env->NewFloatArray(0);
126 }
127
128 hidl_vec<CoolingDevice> list;
129 Return<void> ret = gThermalHal->getCoolingDevices(
130 [&list](ThermalStatus status, hidl_vec<CoolingDevice> devices) {
131 if (status.code == ThermalStatusCode::SUCCESS) {
132 list = std::move(devices);
133 } else {
134 ALOGE("Couldn't get fan speeds because of HAL error: %s",
135 status.debugMessage.c_str());
136 }
137 });
138
139 if (!ret.isOk()) {
140 ALOGE("getCoolingDevices failed status: %s", ret.description().c_str());
141 }
142
143 float values[list.size()];
144 for (size_t i = 0; i < list.size(); ++i) {
145 values[i] = list[i].currentValue;
146 }
147 jfloatArray fanSpeeds = env->NewFloatArray(list.size());
148 env->SetFloatArrayRegion(fanSpeeds, 0, list.size(), values);
149 return fanSpeeds;
150 }
151
nativeGetDeviceTemperatures(JNIEnv * env,jclass,int type,int source)152 static jfloatArray nativeGetDeviceTemperatures(JNIEnv *env, jclass /* clazz */, int type,
153 int source) {
154 std::lock_guard<std::mutex> lock(gThermalHalMutex);
155 getThermalHalLocked();
156 if (gThermalHal == nullptr) {
157 ALOGE("Couldn't get device temperatures because of HAL error.");
158 return env->NewFloatArray(0);
159 }
160 hidl_vec<Temperature> list;
161 Return<void> ret = gThermalHal->getTemperatures(
162 [&list](ThermalStatus status, hidl_vec<Temperature> temperatures) {
163 if (status.code == ThermalStatusCode::SUCCESS) {
164 list = std::move(temperatures);
165 } else {
166 ALOGE("Couldn't get temperatures because of HAL error: %s",
167 status.debugMessage.c_str());
168 }
169 });
170
171 if (!ret.isOk()) {
172 ALOGE("getDeviceTemperatures failed status: %s", ret.description().c_str());
173 }
174
175 jfloat values[list.size()];
176 size_t length = 0;
177 for (size_t i = 0; i < list.size(); ++i) {
178 if (static_cast<int>(list[i].type) == type) {
179 switch (source) {
180 case TEMPERATURE_CURRENT:
181 values[length++] = finalizeTemperature(list[i].currentValue);
182 break;
183 case TEMPERATURE_THROTTLING:
184 values[length++] = finalizeTemperature(list[i].throttlingThreshold);
185 break;
186 case TEMPERATURE_SHUTDOWN:
187 values[length++] = finalizeTemperature(list[i].shutdownThreshold);
188 break;
189 case TEMPERATURE_THROTTLING_BELOW_VR_MIN:
190 values[length++] = finalizeTemperature(list[i].vrThrottlingThreshold);
191 break;
192 }
193 }
194 }
195 jfloatArray deviceTemps = env->NewFloatArray(length);
196 env->SetFloatArrayRegion(deviceTemps, 0, length, values);
197 return deviceTemps;
198 }
199
nativeGetCpuUsages(JNIEnv * env,jclass)200 static jobjectArray nativeGetCpuUsages(JNIEnv *env, jclass /* clazz */) {
201 std::lock_guard<std::mutex> lock(gThermalHalMutex);
202 getThermalHalLocked();
203 if (gThermalHal == nullptr || !gCpuUsageInfoClassInfo.initMethod) {
204 ALOGE("Couldn't get CPU usages because of HAL error.");
205 return env->NewObjectArray(0, gCpuUsageInfoClassInfo.clazz, nullptr);
206 }
207 hidl_vec<CpuUsage> list;
208 Return<void> ret = gThermalHal->getCpuUsages(
209 [&list](ThermalStatus status, hidl_vec<CpuUsage> cpuUsages) {
210 if (status.code == ThermalStatusCode::SUCCESS) {
211 list = std::move(cpuUsages);
212 } else {
213 ALOGE("Couldn't get CPU usages because of HAL error: %s",
214 status.debugMessage.c_str());
215 }
216 });
217
218 if (!ret.isOk()) {
219 ALOGE("getCpuUsages failed status: %s", ret.description().c_str());
220 }
221
222 jobjectArray cpuUsages = env->NewObjectArray(list.size(), gCpuUsageInfoClassInfo.clazz,
223 nullptr);
224 for (size_t i = 0; i < list.size(); ++i) {
225 if (list[i].isOnline) {
226 jobject cpuUsage = env->NewObject(gCpuUsageInfoClassInfo.clazz,
227 gCpuUsageInfoClassInfo.initMethod,
228 list[i].active,
229 list[i].total);
230 env->SetObjectArrayElement(cpuUsages, i, cpuUsage);
231 }
232 }
233 return cpuUsages;
234 }
235
236 // ----------------------------------------------------------------------------
237
238 static const JNINativeMethod gHardwarePropertiesManagerServiceMethods[] = {
239 /* name, signature, funcPtr */
240 { "nativeInit", "()V",
241 (void*) nativeInit },
242 { "nativeGetFanSpeeds", "()[F",
243 (void*) nativeGetFanSpeeds },
244 { "nativeGetDeviceTemperatures", "(II)[F",
245 (void*) nativeGetDeviceTemperatures },
246 { "nativeGetCpuUsages", "()[Landroid/os/CpuUsageInfo;",
247 (void*) nativeGetCpuUsages }
248 };
249
register_android_server_HardwarePropertiesManagerService(JNIEnv * env)250 int register_android_server_HardwarePropertiesManagerService(JNIEnv* env) {
251 int res = jniRegisterNativeMethods(env, "com/android/server/HardwarePropertiesManagerService",
252 gHardwarePropertiesManagerServiceMethods,
253 NELEM(gHardwarePropertiesManagerServiceMethods));
254 jclass clazz = env->FindClass("android/os/CpuUsageInfo");
255 gCpuUsageInfoClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
256 gCpuUsageInfoClassInfo.initMethod = GetMethodIDOrDie(env, gCpuUsageInfoClassInfo.clazz,
257 "<init>", "(JJ)V");
258
259 clazz = env->FindClass("android/os/HardwarePropertiesManager");
260 jfieldID undefined_temperature_field = GetStaticFieldIDOrDie(env, clazz,
261 "UNDEFINED_TEMPERATURE", "F");
262 gUndefinedTemperature = env->GetStaticFloatField(clazz, undefined_temperature_field);
263
264 return res;
265 }
266
267 } /* namespace android */
268