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 "JNIHelp.h"
     22 #include "jni.h"
     23 
     24 #include <ScopedUtfChars.h>
     25 
     26 #include <limits.h>
     27 
     28 #include <android_runtime/AndroidRuntime.h>
     29 #include <utils/Timers.h>
     30 #include <utils/misc.h>
     31 #include <utils/String8.h>
     32 #include <utils/Log.h>
     33 #include <hardware/power.h>
     34 #include <hardware_legacy/power.h>
     35 #include <cutils/android_reboot.h>
     36 #include <suspend/autosuspend.h>
     37 
     38 #include "com_android_server_power_PowerManagerService.h"
     39 
     40 namespace android {
     41 
     42 // ----------------------------------------------------------------------------
     43 
     44 static struct {
     45     jmethodID wakeUpFromNative;
     46     jmethodID goToSleepFromNative;
     47     jmethodID userActivityFromNative;
     48 } gPowerManagerServiceClassInfo;
     49 
     50 // ----------------------------------------------------------------------------
     51 
     52 static jobject gPowerManagerServiceObj;
     53 static struct power_module* gPowerModule;
     54 
     55 static Mutex gPowerManagerLock;
     56 static bool gScreenOn;
     57 static bool gScreenBright;
     58 
     59 static nsecs_t gLastEventTime[USER_ACTIVITY_EVENT_LAST + 1];
     60 
     61 // Throttling interval for user activity calls.
     62 static const nsecs_t MIN_TIME_BETWEEN_USERACTIVITIES = 500 * 1000000L; // 500ms
     63 
     64 // ----------------------------------------------------------------------------
     65 
     66 static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
     67     if (env->ExceptionCheck()) {
     68         ALOGE("An exception was thrown by callback '%s'.", methodName);
     69         LOGE_EX(env);
     70         env->ExceptionClear();
     71         return true;
     72     }
     73     return false;
     74 }
     75 
     76 bool android_server_PowerManagerService_isScreenOn() {
     77     AutoMutex _l(gPowerManagerLock);
     78     return gScreenOn;
     79 }
     80 
     81 bool android_server_PowerManagerService_isScreenBright() {
     82     AutoMutex _l(gPowerManagerLock);
     83     return gScreenBright;
     84 }
     85 
     86 void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
     87     // Tell the power HAL when user activity occurs.
     88     if (gPowerModule && gPowerModule->powerHint) {
     89         gPowerModule->powerHint(gPowerModule, POWER_HINT_INTERACTION, NULL);
     90     }
     91 
     92     if (gPowerManagerServiceObj) {
     93         // Throttle calls into user activity by event type.
     94         // We're a little conservative about argument checking here in case the caller
     95         // passes in bad data which could corrupt system state.
     96         if (eventType >= 0 && eventType <= USER_ACTIVITY_EVENT_LAST) {
     97             nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
     98             if (eventTime > now) {
     99                 eventTime = now;
    100             }
    101 
    102             if (gLastEventTime[eventType] + MIN_TIME_BETWEEN_USERACTIVITIES > eventTime) {
    103                 return;
    104             }
    105             gLastEventTime[eventType] = eventTime;
    106         }
    107 
    108         JNIEnv* env = AndroidRuntime::getJNIEnv();
    109 
    110         env->CallVoidMethod(gPowerManagerServiceObj,
    111                 gPowerManagerServiceClassInfo.userActivityFromNative,
    112                 nanoseconds_to_milliseconds(eventTime), eventType, 0);
    113         checkAndClearExceptionFromCallback(env, "userActivityFromNative");
    114     }
    115 }
    116 
    117 void android_server_PowerManagerService_wakeUp(nsecs_t eventTime) {
    118     if (gPowerManagerServiceObj) {
    119         JNIEnv* env = AndroidRuntime::getJNIEnv();
    120 
    121         env->CallVoidMethod(gPowerManagerServiceObj,
    122                 gPowerManagerServiceClassInfo.wakeUpFromNative,
    123                 nanoseconds_to_milliseconds(eventTime));
    124         checkAndClearExceptionFromCallback(env, "wakeUpFromNative");
    125     }
    126 }
    127 
    128 void android_server_PowerManagerService_goToSleep(nsecs_t eventTime) {
    129     if (gPowerManagerServiceObj) {
    130         JNIEnv* env = AndroidRuntime::getJNIEnv();
    131 
    132         env->CallVoidMethod(gPowerManagerServiceObj,
    133                 gPowerManagerServiceClassInfo.goToSleepFromNative,
    134                 nanoseconds_to_milliseconds(eventTime), 0);
    135         checkAndClearExceptionFromCallback(env, "goToSleepFromNative");
    136     }
    137 }
    138 
    139 // ----------------------------------------------------------------------------
    140 
    141 static void nativeInit(JNIEnv* env, jobject obj) {
    142     gPowerManagerServiceObj = env->NewGlobalRef(obj);
    143 
    144     status_t err = hw_get_module(POWER_HARDWARE_MODULE_ID,
    145             (hw_module_t const**)&gPowerModule);
    146     if (!err) {
    147         gPowerModule->init(gPowerModule);
    148     } else {
    149         ALOGE("Couldn't load %s module (%s)", POWER_HARDWARE_MODULE_ID, strerror(-err));
    150     }
    151 }
    152 
    153 static void nativeSetPowerState(JNIEnv* env,
    154         jclass clazz, jboolean screenOn, jboolean screenBright) {
    155     AutoMutex _l(gPowerManagerLock);
    156     gScreenOn = screenOn;
    157     gScreenBright = screenBright;
    158 }
    159 
    160 static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {
    161     ScopedUtfChars name(env, nameStr);
    162     acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
    163 }
    164 
    165 static void nativeReleaseSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {
    166     ScopedUtfChars name(env, nameStr);
    167     release_wake_lock(name.c_str());
    168 }
    169 
    170 static void nativeSetInteractive(JNIEnv *env, jclass clazz, jboolean enable) {
    171     if (gPowerModule) {
    172         if (enable) {
    173             ALOGD_IF_SLOW(20, "Excessive delay in setInteractive(true) while turning screen on");
    174             gPowerModule->setInteractive(gPowerModule, true);
    175         } else {
    176             ALOGD_IF_SLOW(20, "Excessive delay in setInteractive(false) while turning screen off");
    177             gPowerModule->setInteractive(gPowerModule, false);
    178         }
    179     }
    180 }
    181 
    182 static void nativeSetAutoSuspend(JNIEnv *env, jclass clazz, jboolean enable) {
    183     if (enable) {
    184         ALOGD_IF_SLOW(100, "Excessive delay in autosuspend_enable() while turning screen off");
    185         autosuspend_enable();
    186     } else {
    187         ALOGD_IF_SLOW(100, "Excessive delay in autosuspend_disable() while turning screen on");
    188         autosuspend_disable();
    189     }
    190 }
    191 
    192 static void nativeShutdown(JNIEnv *env, jclass clazz) {
    193     android_reboot(ANDROID_RB_POWEROFF, 0, 0);
    194 }
    195 
    196 static void nativeReboot(JNIEnv *env, jclass clazz, jstring reason) {
    197     if (reason == NULL) {
    198         android_reboot(ANDROID_RB_RESTART, 0, 0);
    199     } else {
    200         const char *chars = env->GetStringUTFChars(reason, NULL);
    201         android_reboot(ANDROID_RB_RESTART2, 0, (char *) chars);
    202         env->ReleaseStringUTFChars(reason, chars);  // In case it fails.
    203     }
    204     jniThrowIOException(env, errno);
    205 }
    206 
    207 
    208 // ----------------------------------------------------------------------------
    209 
    210 static JNINativeMethod gPowerManagerServiceMethods[] = {
    211     /* name, signature, funcPtr */
    212     { "nativeInit", "()V",
    213             (void*) nativeInit },
    214     { "nativeSetPowerState", "(ZZ)V",
    215             (void*) nativeSetPowerState },
    216     { "nativeAcquireSuspendBlocker", "(Ljava/lang/String;)V",
    217             (void*) nativeAcquireSuspendBlocker },
    218     { "nativeReleaseSuspendBlocker", "(Ljava/lang/String;)V",
    219             (void*) nativeReleaseSuspendBlocker },
    220     { "nativeSetInteractive", "(Z)V",
    221             (void*) nativeSetInteractive },
    222     { "nativeSetAutoSuspend", "(Z)V",
    223             (void*) nativeSetAutoSuspend },
    224     { "nativeShutdown", "()V",
    225             (void*) nativeShutdown },
    226     { "nativeReboot", "(Ljava/lang/String;)V",
    227             (void*) nativeReboot },
    228 };
    229 
    230 #define FIND_CLASS(var, className) \
    231         var = env->FindClass(className); \
    232         LOG_FATAL_IF(! var, "Unable to find class " className);
    233 
    234 #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
    235         var = env->GetMethodID(clazz, methodName, methodDescriptor); \
    236         LOG_FATAL_IF(! var, "Unable to find method " methodName);
    237 
    238 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
    239         var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
    240         LOG_FATAL_IF(! var, "Unable to find field " fieldName);
    241 
    242 int register_android_server_PowerManagerService(JNIEnv* env) {
    243     int res = jniRegisterNativeMethods(env, "com/android/server/power/PowerManagerService",
    244             gPowerManagerServiceMethods, NELEM(gPowerManagerServiceMethods));
    245     LOG_FATAL_IF(res < 0, "Unable to register native methods.");
    246 
    247     // Callbacks
    248 
    249     jclass clazz;
    250     FIND_CLASS(clazz, "com/android/server/power/PowerManagerService");
    251 
    252     GET_METHOD_ID(gPowerManagerServiceClassInfo.wakeUpFromNative, clazz,
    253             "wakeUpFromNative", "(J)V");
    254 
    255     GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleepFromNative, clazz,
    256             "goToSleepFromNative", "(JI)V");
    257 
    258     GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivityFromNative, clazz,
    259             "userActivityFromNative", "(JII)V");
    260 
    261     // Initialize
    262     for (int i = 0; i <= USER_ACTIVITY_EVENT_LAST; i++) {
    263         gLastEventTime[i] = LLONG_MIN;
    264     }
    265     gScreenOn = true;
    266     gScreenBright = true;
    267     gPowerManagerServiceObj = NULL;
    268     gPowerModule = NULL;
    269     return 0;
    270 }
    271 
    272 } /* namespace android */
    273