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 "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 hardware::hidl_vec;
34 using hardware::thermal::V1_0::CoolingDevice;
35 using hardware::thermal::V1_0::CpuUsage;
36 using hardware::thermal::V1_0::IThermal;
37 using hardware::thermal::V1_0::Temperature;
38 using hardware::thermal::V1_0::ThermalStatus;
39 using hardware::thermal::V1_0::ThermalStatusCode;
40 template<typename T>
41 using Return = hardware::Return<T>;
42
43 // ---------------------------------------------------------------------------
44
45 // These values must be kept in sync with the temperature source constants in
46 // HardwarePropertiesManager.java
47 enum {
48 TEMPERATURE_CURRENT = 0,
49 TEMPERATURE_THROTTLING = 1,
50 TEMPERATURE_SHUTDOWN = 2,
51 TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3
52 };
53
54 static struct {
55 jclass clazz;
56 jmethodID initMethod;
57 } gCpuUsageInfoClassInfo;
58
59 jfloat gUndefinedTemperature;
60
61 static sp<IThermal> gThermalModule;
62
63 // ----------------------------------------------------------------------------
64
finalizeTemperature(float temperature)65 float finalizeTemperature(float temperature) {
66 return isnan(temperature) ? gUndefinedTemperature : temperature;
67 }
68
nativeInit(JNIEnv * env,jobject obj)69 static void nativeInit(JNIEnv* env, jobject obj) {
70 // TODO(b/31632518)
71 if (gThermalModule == nullptr) {
72 gThermalModule = IThermal::getService();
73 }
74
75 if (gThermalModule == nullptr) {
76 ALOGE("Unable to get Thermal service.");
77 }
78 }
79
nativeGetFanSpeeds(JNIEnv * env,jclass)80 static jfloatArray nativeGetFanSpeeds(JNIEnv *env, jclass /* clazz */) {
81 if (gThermalModule == nullptr) {
82 ALOGE("Couldn't get fan speeds because of HAL error.");
83 return env->NewFloatArray(0);
84 }
85
86 hidl_vec<CoolingDevice> list;
87 Return<void> ret = gThermalModule->getCoolingDevices(
88 [&list](ThermalStatus status, hidl_vec<CoolingDevice> devices) {
89 if (status.code == ThermalStatusCode::SUCCESS) {
90 list = std::move(devices);
91 } else {
92 ALOGE("Couldn't get fan speeds because of HAL error: %s",
93 status.debugMessage.c_str());
94 }
95 });
96
97 if (!ret.isOk()) {
98 ALOGE("getCoolingDevices failed status: %s", ret.description().c_str());
99 }
100
101 float values[list.size()];
102 for (size_t i = 0; i < list.size(); ++i) {
103 values[i] = list[i].currentValue;
104 }
105 jfloatArray fanSpeeds = env->NewFloatArray(list.size());
106 env->SetFloatArrayRegion(fanSpeeds, 0, list.size(), values);
107 return fanSpeeds;
108 }
109
nativeGetDeviceTemperatures(JNIEnv * env,jclass,int type,int source)110 static jfloatArray nativeGetDeviceTemperatures(JNIEnv *env, jclass /* clazz */, int type,
111 int source) {
112 if (gThermalModule == nullptr) {
113 ALOGE("Couldn't get device temperatures because of HAL error.");
114 return env->NewFloatArray(0);
115 }
116 hidl_vec<Temperature> list;
117 Return<void> ret = gThermalModule->getTemperatures(
118 [&list](ThermalStatus status, hidl_vec<Temperature> temperatures) {
119 if (status.code == ThermalStatusCode::SUCCESS) {
120 list = std::move(temperatures);
121 } else {
122 ALOGE("Couldn't get temperatures because of HAL error: %s",
123 status.debugMessage.c_str());
124 }
125 });
126
127 if (!ret.isOk()) {
128 ALOGE("getDeviceTemperatures failed status: %s", ret.description().c_str());
129 }
130
131 jfloat values[list.size()];
132 size_t length = 0;
133 for (size_t i = 0; i < list.size(); ++i) {
134 if (static_cast<int>(list[i].type) == type) {
135 switch (source) {
136 case TEMPERATURE_CURRENT:
137 values[length++] = finalizeTemperature(list[i].currentValue);
138 break;
139 case TEMPERATURE_THROTTLING:
140 values[length++] = finalizeTemperature(list[i].throttlingThreshold);
141 break;
142 case TEMPERATURE_SHUTDOWN:
143 values[length++] = finalizeTemperature(list[i].shutdownThreshold);
144 break;
145 case TEMPERATURE_THROTTLING_BELOW_VR_MIN:
146 values[length++] = finalizeTemperature(list[i].vrThrottlingThreshold);
147 break;
148 }
149 }
150 }
151 jfloatArray deviceTemps = env->NewFloatArray(length);
152 env->SetFloatArrayRegion(deviceTemps, 0, length, values);
153 return deviceTemps;
154 }
155
nativeGetCpuUsages(JNIEnv * env,jclass)156 static jobjectArray nativeGetCpuUsages(JNIEnv *env, jclass /* clazz */) {
157 if (gThermalModule == nullptr || !gCpuUsageInfoClassInfo.initMethod) {
158 ALOGE("Couldn't get CPU usages because of HAL error.");
159 return env->NewObjectArray(0, gCpuUsageInfoClassInfo.clazz, nullptr);
160 }
161 hidl_vec<CpuUsage> list;
162 Return<void> ret = gThermalModule->getCpuUsages(
163 [&list](ThermalStatus status, hidl_vec<CpuUsage> cpuUsages) {
164 if (status.code == ThermalStatusCode::SUCCESS) {
165 list = std::move(cpuUsages);
166 } else {
167 ALOGE("Couldn't get CPU usages because of HAL error: %s",
168 status.debugMessage.c_str());
169 }
170 });
171
172 if (!ret.isOk()) {
173 ALOGE("getCpuUsages failed status: %s", ret.description().c_str());
174 }
175
176 jobjectArray cpuUsages = env->NewObjectArray(list.size(), gCpuUsageInfoClassInfo.clazz,
177 nullptr);
178 for (size_t i = 0; i < list.size(); ++i) {
179 if (list[i].isOnline) {
180 jobject cpuUsage = env->NewObject(gCpuUsageInfoClassInfo.clazz,
181 gCpuUsageInfoClassInfo.initMethod,
182 list[i].active,
183 list[i].total);
184 env->SetObjectArrayElement(cpuUsages, i, cpuUsage);
185 }
186 }
187 return cpuUsages;
188 }
189
190 // ----------------------------------------------------------------------------
191
192 static const JNINativeMethod gHardwarePropertiesManagerServiceMethods[] = {
193 /* name, signature, funcPtr */
194 { "nativeInit", "()V",
195 (void*) nativeInit },
196 { "nativeGetFanSpeeds", "()[F",
197 (void*) nativeGetFanSpeeds },
198 { "nativeGetDeviceTemperatures", "(II)[F",
199 (void*) nativeGetDeviceTemperatures },
200 { "nativeGetCpuUsages", "()[Landroid/os/CpuUsageInfo;",
201 (void*) nativeGetCpuUsages }
202 };
203
register_android_server_HardwarePropertiesManagerService(JNIEnv * env)204 int register_android_server_HardwarePropertiesManagerService(JNIEnv* env) {
205 gThermalModule = nullptr;
206 int res = jniRegisterNativeMethods(env, "com/android/server/HardwarePropertiesManagerService",
207 gHardwarePropertiesManagerServiceMethods,
208 NELEM(gHardwarePropertiesManagerServiceMethods));
209 jclass clazz = env->FindClass("android/os/CpuUsageInfo");
210 gCpuUsageInfoClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
211 gCpuUsageInfoClassInfo.initMethod = GetMethodIDOrDie(env, gCpuUsageInfoClassInfo.clazz,
212 "<init>", "(JJ)V");
213
214 clazz = env->FindClass("android/os/HardwarePropertiesManager");
215 jfieldID undefined_temperature_field = GetStaticFieldIDOrDie(env, clazz,
216 "UNDEFINED_TEMPERATURE", "F");
217 gUndefinedTemperature = env->GetStaticFloatField(clazz, undefined_temperature_field);
218
219 return res;
220 }
221
222 } /* namespace android */
223