Home | History | Annotate | Download | only in jni
      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