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 70 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 82 float finalizeTemperature(float temperature) { 83 return isnan(temperature) ? gUndefinedTemperature : temperature; 84 } 85 86 // The caller must be holding gThermalHalMutex. 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 115 static void nativeInit(JNIEnv* env, jobject obj) { 116 std::lock_guard<std::mutex> lock(gThermalHalMutex); 117 getThermalHalLocked(); 118 } 119 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 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 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 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