/*
|
* 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 <nativehelper/JNIHelp.h>
|
#include "jni.h"
|
|
#include <math.h>
|
#include <stdlib.h>
|
|
#include <android/hardware/thermal/1.0/IThermal.h>
|
#include <utils/Log.h>
|
#include <utils/String8.h>
|
|
#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<typename T>
|
using Return = hardware::Return<T>;
|
|
// ---------------------------------------------------------------------------
|
|
// 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<IThermal> gThermalHal = nullptr;
|
|
// struct ThermalHalDeathRecipient;
|
struct ThermalHalDeathRecipient : virtual public hidl_death_recipient {
|
// hidl_death_recipient interface
|
virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override {
|
std::lock_guard<std::mutex> lock(gThermalHalMutex);
|
ALOGE("ThermalHAL just died");
|
gThermalHal = nullptr;
|
getThermalHalLocked();
|
}
|
};
|
|
sp<ThermalHalDeathRecipient> 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<bool> 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<std::mutex> lock(gThermalHalMutex);
|
getThermalHalLocked();
|
}
|
|
static jfloatArray nativeGetFanSpeeds(JNIEnv *env, jclass /* clazz */) {
|
std::lock_guard<std::mutex> lock(gThermalHalMutex);
|
getThermalHalLocked();
|
if (gThermalHal == nullptr) {
|
ALOGE("Couldn't get fan speeds because of HAL error.");
|
return env->NewFloatArray(0);
|
}
|
|
hidl_vec<CoolingDevice> list;
|
Return<void> ret = gThermalHal->getCoolingDevices(
|
[&list](ThermalStatus status, hidl_vec<CoolingDevice> 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<std::mutex> lock(gThermalHalMutex);
|
getThermalHalLocked();
|
if (gThermalHal == nullptr) {
|
ALOGE("Couldn't get device temperatures because of HAL error.");
|
return env->NewFloatArray(0);
|
}
|
hidl_vec<Temperature> list;
|
Return<void> ret = gThermalHal->getTemperatures(
|
[&list](ThermalStatus status, hidl_vec<Temperature> 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<int>(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<std::mutex> 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<CpuUsage> list;
|
Return<void> ret = gThermalHal->getCpuUsages(
|
[&list](ThermalStatus status, hidl_vec<CpuUsage> 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,
|
"<init>", "(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 */
|