/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "HardwarePropertiesManagerService-JNI" #include #include "jni.h" #include #include #include #include #include #include "core_jni_helpers.h" namespace android { using android::hidl::base::V1_0::IBase; using hardware::hidl_death_recipient; using hardware::hidl_vec; using hardware::thermal::V1_0::CoolingDevice; using hardware::thermal::V1_0::CpuUsage; using hardware::thermal::V1_0::IThermal; using hardware::thermal::V1_0::Temperature; using hardware::thermal::V1_0::ThermalStatus; using hardware::thermal::V1_0::ThermalStatusCode; template using Return = hardware::Return; // --------------------------------------------------------------------------- // These values must be kept in sync with the temperature source constants in // HardwarePropertiesManager.java enum { TEMPERATURE_CURRENT = 0, TEMPERATURE_THROTTLING = 1, TEMPERATURE_SHUTDOWN = 2, TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3 }; static struct { jclass clazz; jmethodID initMethod; } gCpuUsageInfoClassInfo; jfloat gUndefinedTemperature; static void getThermalHalLocked(); static std::mutex gThermalHalMutex; static sp gThermalHal = nullptr; // struct ThermalHalDeathRecipient; struct ThermalHalDeathRecipient : virtual public hidl_death_recipient { // hidl_death_recipient interface virtual void serviceDied(uint64_t cookie, const wp& who) override { std::lock_guard lock(gThermalHalMutex); ALOGE("ThermalHAL just died"); gThermalHal = nullptr; getThermalHalLocked(); } }; sp gThermalHalDeathRecipient = nullptr; // ---------------------------------------------------------------------------- float finalizeTemperature(float temperature) { return isnan(temperature) ? gUndefinedTemperature : temperature; } // The caller must be holding gThermalHalMutex. static void getThermalHalLocked() { if (gThermalHal != nullptr) { return; } gThermalHal = IThermal::getService(); if (gThermalHal == nullptr) { ALOGE("Unable to get Thermal service."); } else { if (gThermalHalDeathRecipient == nullptr) { gThermalHalDeathRecipient = new ThermalHalDeathRecipient(); } hardware::Return linked = gThermalHal->linkToDeath( gThermalHalDeathRecipient, 0x451F /* cookie */); if (!linked.isOk()) { ALOGE("Transaction error in linking to ThermalHAL death: %s", linked.description().c_str()); gThermalHal = nullptr; } else if (!linked) { ALOGW("Unable to link to ThermalHal death notifications"); gThermalHal = nullptr; } else { ALOGD("Link to death notification successful"); } } } static void nativeInit(JNIEnv* env, jobject obj) { std::lock_guard lock(gThermalHalMutex); getThermalHalLocked(); } static jfloatArray nativeGetFanSpeeds(JNIEnv *env, jclass /* clazz */) { std::lock_guard lock(gThermalHalMutex); getThermalHalLocked(); if (gThermalHal == nullptr) { ALOGE("Couldn't get fan speeds because of HAL error."); return env->NewFloatArray(0); } hidl_vec list; Return ret = gThermalHal->getCoolingDevices( [&list](ThermalStatus status, hidl_vec devices) { if (status.code == ThermalStatusCode::SUCCESS) { list = std::move(devices); } else { ALOGE("Couldn't get fan speeds because of HAL error: %s", status.debugMessage.c_str()); } }); if (!ret.isOk()) { ALOGE("getCoolingDevices failed status: %s", ret.description().c_str()); } float values[list.size()]; for (size_t i = 0; i < list.size(); ++i) { values[i] = list[i].currentValue; } jfloatArray fanSpeeds = env->NewFloatArray(list.size()); env->SetFloatArrayRegion(fanSpeeds, 0, list.size(), values); return fanSpeeds; } static jfloatArray nativeGetDeviceTemperatures(JNIEnv *env, jclass /* clazz */, int type, int source) { std::lock_guard lock(gThermalHalMutex); getThermalHalLocked(); if (gThermalHal == nullptr) { ALOGE("Couldn't get device temperatures because of HAL error."); return env->NewFloatArray(0); } hidl_vec list; Return ret = gThermalHal->getTemperatures( [&list](ThermalStatus status, hidl_vec temperatures) { if (status.code == ThermalStatusCode::SUCCESS) { list = std::move(temperatures); } else { ALOGE("Couldn't get temperatures because of HAL error: %s", status.debugMessage.c_str()); } }); if (!ret.isOk()) { ALOGE("getDeviceTemperatures failed status: %s", ret.description().c_str()); } jfloat values[list.size()]; size_t length = 0; for (size_t i = 0; i < list.size(); ++i) { if (static_cast(list[i].type) == type) { switch (source) { case TEMPERATURE_CURRENT: values[length++] = finalizeTemperature(list[i].currentValue); break; case TEMPERATURE_THROTTLING: values[length++] = finalizeTemperature(list[i].throttlingThreshold); break; case TEMPERATURE_SHUTDOWN: values[length++] = finalizeTemperature(list[i].shutdownThreshold); break; case TEMPERATURE_THROTTLING_BELOW_VR_MIN: values[length++] = finalizeTemperature(list[i].vrThrottlingThreshold); break; } } } jfloatArray deviceTemps = env->NewFloatArray(length); env->SetFloatArrayRegion(deviceTemps, 0, length, values); return deviceTemps; } static jobjectArray nativeGetCpuUsages(JNIEnv *env, jclass /* clazz */) { std::lock_guard lock(gThermalHalMutex); getThermalHalLocked(); if (gThermalHal == nullptr || !gCpuUsageInfoClassInfo.initMethod) { ALOGE("Couldn't get CPU usages because of HAL error."); return env->NewObjectArray(0, gCpuUsageInfoClassInfo.clazz, nullptr); } hidl_vec list; Return ret = gThermalHal->getCpuUsages( [&list](ThermalStatus status, hidl_vec cpuUsages) { if (status.code == ThermalStatusCode::SUCCESS) { list = std::move(cpuUsages); } else { ALOGE("Couldn't get CPU usages because of HAL error: %s", status.debugMessage.c_str()); } }); if (!ret.isOk()) { ALOGE("getCpuUsages failed status: %s", ret.description().c_str()); } jobjectArray cpuUsages = env->NewObjectArray(list.size(), gCpuUsageInfoClassInfo.clazz, nullptr); for (size_t i = 0; i < list.size(); ++i) { if (list[i].isOnline) { jobject cpuUsage = env->NewObject(gCpuUsageInfoClassInfo.clazz, gCpuUsageInfoClassInfo.initMethod, list[i].active, list[i].total); env->SetObjectArrayElement(cpuUsages, i, cpuUsage); } } return cpuUsages; } // ---------------------------------------------------------------------------- static const JNINativeMethod gHardwarePropertiesManagerServiceMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "()V", (void*) nativeInit }, { "nativeGetFanSpeeds", "()[F", (void*) nativeGetFanSpeeds }, { "nativeGetDeviceTemperatures", "(II)[F", (void*) nativeGetDeviceTemperatures }, { "nativeGetCpuUsages", "()[Landroid/os/CpuUsageInfo;", (void*) nativeGetCpuUsages } }; int register_android_server_HardwarePropertiesManagerService(JNIEnv* env) { int res = jniRegisterNativeMethods(env, "com/android/server/HardwarePropertiesManagerService", gHardwarePropertiesManagerServiceMethods, NELEM(gHardwarePropertiesManagerServiceMethods)); jclass clazz = env->FindClass("android/os/CpuUsageInfo"); gCpuUsageInfoClassInfo.clazz = MakeGlobalRefOrDie(env, clazz); gCpuUsageInfoClassInfo.initMethod = GetMethodIDOrDie(env, gCpuUsageInfoClassInfo.clazz, "", "(JJ)V"); clazz = env->FindClass("android/os/HardwarePropertiesManager"); jfieldID undefined_temperature_field = GetStaticFieldIDOrDie(env, clazz, "UNDEFINED_TEMPERATURE", "F"); gUndefinedTemperature = env->GetStaticFloatField(clazz, undefined_temperature_field); return res; } } /* namespace android */