Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2010 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 "PowerManagerService-JNI"
     18 
     19 //#define LOG_NDEBUG 0
     20 
     21 #include <android/hardware/power/1.1/IPower.h>
     22 #include <nativehelper/JNIHelp.h>
     23 #include "jni.h"
     24 
     25 #include <nativehelper/ScopedUtfChars.h>
     26 
     27 #include <limits.h>
     28 
     29 #include <android-base/chrono_utils.h>
     30 #include <android_runtime/AndroidRuntime.h>
     31 #include <android_runtime/Log.h>
     32 #include <utils/Timers.h>
     33 #include <utils/misc.h>
     34 #include <utils/String8.h>
     35 #include <utils/Log.h>
     36 #include <hardware/power.h>
     37 #include <hardware_legacy/power.h>
     38 #include <suspend/autosuspend.h>
     39 
     40 #include "com_android_server_power_PowerManagerService.h"
     41 
     42 using android::hardware::Return;
     43 using android::hardware::Void;
     44 using android::hardware::power::V1_0::PowerHint;
     45 using android::hardware::power::V1_0::Feature;
     46 using android::String8;
     47 using IPowerV1_1 = android::hardware::power::V1_1::IPower;
     48 using IPowerV1_0 = android::hardware::power::V1_0::IPower;
     49 
     50 namespace android {
     51 
     52 // ----------------------------------------------------------------------------
     53 
     54 static struct {
     55     jmethodID userActivityFromNative;
     56 } gPowerManagerServiceClassInfo;
     57 
     58 // ----------------------------------------------------------------------------
     59 
     60 static jobject gPowerManagerServiceObj;
     61 // Use getPowerHal* to retrieve a copy
     62 static sp<IPowerV1_0> gPowerHalV1_0_ = nullptr;
     63 static sp<IPowerV1_1> gPowerHalV1_1_ = nullptr;
     64 static bool gPowerHalExists = true;
     65 static std::mutex gPowerHalMutex;
     66 static nsecs_t gLastEventTime[USER_ACTIVITY_EVENT_LAST + 1];
     67 
     68 // Throttling interval for user activity calls.
     69 static const nsecs_t MIN_TIME_BETWEEN_USERACTIVITIES = 100 * 1000000L; // 100ms
     70 
     71 // ----------------------------------------------------------------------------
     72 
     73 static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
     74     if (env->ExceptionCheck()) {
     75         ALOGE("An exception was thrown by callback '%s'.", methodName);
     76         LOGE_EX(env);
     77         env->ExceptionClear();
     78         return true;
     79     }
     80     return false;
     81 }
     82 
     83 // Check validity of current handle to the power HAL service, and call getService() if necessary.
     84 // The caller must be holding gPowerHalMutex.
     85 static void connectPowerHalLocked() {
     86     if (gPowerHalExists && gPowerHalV1_0_ == nullptr) {
     87         gPowerHalV1_0_ = IPowerV1_0::getService();
     88         if (gPowerHalV1_0_ != nullptr) {
     89             ALOGI("Loaded power HAL 1.0 service");
     90             // Try cast to powerHAL V1_1
     91             gPowerHalV1_1_ =  IPowerV1_1::castFrom(gPowerHalV1_0_);
     92             if (gPowerHalV1_1_ == nullptr) {
     93             } else {
     94                 ALOGI("Loaded power HAL 1.1 service");
     95             }
     96         } else {
     97             ALOGI("Couldn't load power HAL service");
     98             gPowerHalExists = false;
     99         }
    100     }
    101 }
    102 
    103 // Retrieve a copy of PowerHAL V1_0
    104 sp<IPowerV1_0> getPowerHalV1_0() {
    105     std::lock_guard<std::mutex> lock(gPowerHalMutex);
    106     connectPowerHalLocked();
    107     return gPowerHalV1_0_;
    108 }
    109 
    110 // Retrieve a copy of PowerHAL V1_1
    111 sp<IPowerV1_1> getPowerHalV1_1() {
    112     std::lock_guard<std::mutex> lock(gPowerHalMutex);
    113     connectPowerHalLocked();
    114     return gPowerHalV1_1_;
    115 }
    116 
    117 // Check if a call to a power HAL function failed; if so, log the failure and invalidate the
    118 // current handle to the power HAL service.
    119 bool processPowerHalReturn(const Return<void> &ret, const char* functionName) {
    120     if (!ret.isOk()) {
    121         ALOGE("%s() failed: power HAL service not available.", functionName);
    122         gPowerHalMutex.lock();
    123         gPowerHalV1_0_ = nullptr;
    124         gPowerHalV1_1_ = nullptr;
    125         gPowerHalMutex.unlock();
    126     }
    127     return ret.isOk();
    128 }
    129 
    130 static void sendPowerHint(PowerHint hintId, uint32_t data) {
    131     sp<IPowerV1_1> powerHalV1_1 = getPowerHalV1_1();
    132     Return<void> ret;
    133     if (powerHalV1_1 != nullptr) {
    134         ret = powerHalV1_1->powerHintAsync(hintId, data);
    135         processPowerHalReturn(ret, "powerHintAsync");
    136     } else {
    137         sp<IPowerV1_0> powerHalV1_0 = getPowerHalV1_0();
    138         if (powerHalV1_0 != nullptr) {
    139             ret = powerHalV1_0->powerHint(hintId, data);
    140             processPowerHalReturn(ret, "powerHint");
    141         }
    142     }
    143 }
    144 
    145 void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
    146     if (gPowerManagerServiceObj) {
    147         // Throttle calls into user activity by event type.
    148         // We're a little conservative about argument checking here in case the caller
    149         // passes in bad data which could corrupt system state.
    150         if (eventType >= 0 && eventType <= USER_ACTIVITY_EVENT_LAST) {
    151             nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
    152             if (eventTime > now) {
    153                 eventTime = now;
    154             }
    155 
    156             if (gLastEventTime[eventType] + MIN_TIME_BETWEEN_USERACTIVITIES > eventTime) {
    157                 return;
    158             }
    159             gLastEventTime[eventType] = eventTime;
    160 
    161             // Tell the power HAL when user activity occurs.
    162             sendPowerHint(PowerHint::INTERACTION, 0);
    163         }
    164 
    165         JNIEnv* env = AndroidRuntime::getJNIEnv();
    166 
    167         env->CallVoidMethod(gPowerManagerServiceObj,
    168                 gPowerManagerServiceClassInfo.userActivityFromNative,
    169                 nanoseconds_to_milliseconds(eventTime), eventType, 0);
    170         checkAndClearExceptionFromCallback(env, "userActivityFromNative");
    171     }
    172 }
    173 
    174 // ----------------------------------------------------------------------------
    175 
    176 static void nativeInit(JNIEnv* env, jobject obj) {
    177     gPowerManagerServiceObj = env->NewGlobalRef(obj);
    178 
    179     gPowerHalMutex.lock();
    180     connectPowerHalLocked();
    181     gPowerHalMutex.unlock();
    182 }
    183 
    184 static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass /* clazz */, jstring nameStr) {
    185     ScopedUtfChars name(env, nameStr);
    186     acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
    187 }
    188 
    189 static void nativeReleaseSuspendBlocker(JNIEnv *env, jclass /* clazz */, jstring nameStr) {
    190     ScopedUtfChars name(env, nameStr);
    191     release_wake_lock(name.c_str());
    192 }
    193 
    194 static void nativeSetInteractive(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) {
    195     sp<IPowerV1_0> powerHalV1_0 = getPowerHalV1_0();
    196     if (powerHalV1_0 != nullptr) {
    197         android::base::Timer t;
    198         Return<void> ret = powerHalV1_0->setInteractive(enable);
    199         processPowerHalReturn(ret, "setInteractive");
    200         if (t.duration() > 20ms) {
    201             ALOGD("Excessive delay in setInteractive(%s) while turning screen %s",
    202                   enable ? "true" : "false", enable ? "on" : "off");
    203         }
    204     }
    205 }
    206 
    207 static void nativeSetAutoSuspend(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) {
    208     if (enable) {
    209         android::base::Timer t;
    210         autosuspend_enable();
    211         if (t.duration() > 100ms) {
    212             ALOGD("Excessive delay in autosuspend_enable() while turning screen off");
    213         }
    214     } else {
    215         android::base::Timer t;
    216         autosuspend_disable();
    217         if (t.duration() > 100ms) {
    218             ALOGD("Excessive delay in autosuspend_disable() while turning screen on");
    219         }
    220     }
    221 }
    222 
    223 static void nativeSendPowerHint(JNIEnv* /* env */, jclass /* clazz */, jint hintId, jint data) {
    224     sendPowerHint(static_cast<PowerHint>(hintId), data);
    225 }
    226 
    227 static void nativeSetFeature(JNIEnv* /* env */, jclass /* clazz */, jint featureId, jint data) {
    228     sp<IPowerV1_0> powerHalV1_0 = getPowerHalV1_0();
    229     if (powerHalV1_0 != nullptr) {
    230         Return<void> ret = powerHalV1_0->setFeature((Feature)featureId, static_cast<bool>(data));
    231         processPowerHalReturn(ret, "setFeature");
    232     }
    233 }
    234 
    235 // ----------------------------------------------------------------------------
    236 
    237 static const JNINativeMethod gPowerManagerServiceMethods[] = {
    238     /* name, signature, funcPtr */
    239     { "nativeInit", "()V",
    240             (void*) nativeInit },
    241     { "nativeAcquireSuspendBlocker", "(Ljava/lang/String;)V",
    242             (void*) nativeAcquireSuspendBlocker },
    243     { "nativeReleaseSuspendBlocker", "(Ljava/lang/String;)V",
    244             (void*) nativeReleaseSuspendBlocker },
    245     { "nativeSetInteractive", "(Z)V",
    246             (void*) nativeSetInteractive },
    247     { "nativeSetAutoSuspend", "(Z)V",
    248             (void*) nativeSetAutoSuspend },
    249     { "nativeSendPowerHint", "(II)V",
    250             (void*) nativeSendPowerHint },
    251     { "nativeSetFeature", "(II)V",
    252             (void*) nativeSetFeature },
    253 };
    254 
    255 #define FIND_CLASS(var, className) \
    256         var = env->FindClass(className); \
    257         LOG_FATAL_IF(! (var), "Unable to find class " className);
    258 
    259 #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
    260         var = env->GetMethodID(clazz, methodName, methodDescriptor); \
    261         LOG_FATAL_IF(! (var), "Unable to find method " methodName);
    262 
    263 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
    264         var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
    265         LOG_FATAL_IF(! (var), "Unable to find field " fieldName);
    266 
    267 int register_android_server_PowerManagerService(JNIEnv* env) {
    268     int res = jniRegisterNativeMethods(env, "com/android/server/power/PowerManagerService",
    269             gPowerManagerServiceMethods, NELEM(gPowerManagerServiceMethods));
    270     (void) res;  // Faked use when LOG_NDEBUG.
    271     LOG_FATAL_IF(res < 0, "Unable to register native methods.");
    272 
    273     // Callbacks
    274 
    275     jclass clazz;
    276     FIND_CLASS(clazz, "com/android/server/power/PowerManagerService");
    277 
    278     GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivityFromNative, clazz,
    279             "userActivityFromNative", "(JII)V");
    280 
    281     // Initialize
    282     for (int i = 0; i <= USER_ACTIVITY_EVENT_LAST; i++) {
    283         gLastEventTime[i] = LLONG_MIN;
    284     }
    285     gPowerManagerServiceObj = NULL;
    286     return 0;
    287 }
    288 
    289 } /* namespace android */
    290