summaryrefslogtreecommitdiffstats
path: root/services/core/jni/com_android_server_power_PowerManagerService.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'services/core/jni/com_android_server_power_PowerManagerService.cpp')
-rw-r--r--services/core/jni/com_android_server_power_PowerManagerService.cpp252
1 files changed, 252 insertions, 0 deletions
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
new file mode 100644
index 0000000..151e134
--- /dev/null
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2010 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 "PowerManagerService-JNI"
+
+//#define LOG_NDEBUG 0
+
+#include "JNIHelp.h"
+#include "jni.h"
+
+#include <ScopedUtfChars.h>
+
+#include <limits.h>
+
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
+#include <utils/Timers.h>
+#include <utils/misc.h>
+#include <utils/String8.h>
+#include <utils/Log.h>
+#include <hardware/power.h>
+#include <hardware_legacy/power.h>
+#include <suspend/autosuspend.h>
+
+#include "com_android_server_power_PowerManagerService.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static struct {
+ jmethodID wakeUpFromNative;
+ jmethodID goToSleepFromNative;
+ jmethodID userActivityFromNative;
+} gPowerManagerServiceClassInfo;
+
+// ----------------------------------------------------------------------------
+
+static jobject gPowerManagerServiceObj;
+static struct power_module* gPowerModule;
+
+static Mutex gPowerManagerLock;
+static bool gScreenOn;
+static bool gScreenBright;
+
+static nsecs_t gLastEventTime[USER_ACTIVITY_EVENT_LAST + 1];
+
+// Throttling interval for user activity calls.
+static const nsecs_t MIN_TIME_BETWEEN_USERACTIVITIES = 500 * 1000000L; // 500ms
+
+// ----------------------------------------------------------------------------
+
+static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
+ if (env->ExceptionCheck()) {
+ ALOGE("An exception was thrown by callback '%s'.", methodName);
+ LOGE_EX(env);
+ env->ExceptionClear();
+ return true;
+ }
+ return false;
+}
+
+bool android_server_PowerManagerService_isScreenOn() {
+ AutoMutex _l(gPowerManagerLock);
+ return gScreenOn;
+}
+
+bool android_server_PowerManagerService_isScreenBright() {
+ AutoMutex _l(gPowerManagerLock);
+ return gScreenBright;
+}
+
+void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
+ // Tell the power HAL when user activity occurs.
+ if (gPowerModule && gPowerModule->powerHint) {
+ gPowerModule->powerHint(gPowerModule, POWER_HINT_INTERACTION, NULL);
+ }
+
+ if (gPowerManagerServiceObj) {
+ // Throttle calls into user activity by event type.
+ // We're a little conservative about argument checking here in case the caller
+ // passes in bad data which could corrupt system state.
+ if (eventType >= 0 && eventType <= USER_ACTIVITY_EVENT_LAST) {
+ nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+ if (eventTime > now) {
+ eventTime = now;
+ }
+
+ if (gLastEventTime[eventType] + MIN_TIME_BETWEEN_USERACTIVITIES > eventTime) {
+ return;
+ }
+ gLastEventTime[eventType] = eventTime;
+ }
+
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+ env->CallVoidMethod(gPowerManagerServiceObj,
+ gPowerManagerServiceClassInfo.userActivityFromNative,
+ nanoseconds_to_milliseconds(eventTime), eventType, 0);
+ checkAndClearExceptionFromCallback(env, "userActivityFromNative");
+ }
+}
+
+void android_server_PowerManagerService_wakeUp(nsecs_t eventTime) {
+ if (gPowerManagerServiceObj) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+ env->CallVoidMethod(gPowerManagerServiceObj,
+ gPowerManagerServiceClassInfo.wakeUpFromNative,
+ nanoseconds_to_milliseconds(eventTime));
+ checkAndClearExceptionFromCallback(env, "wakeUpFromNative");
+ }
+}
+
+void android_server_PowerManagerService_goToSleep(nsecs_t eventTime) {
+ if (gPowerManagerServiceObj) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+ env->CallVoidMethod(gPowerManagerServiceObj,
+ gPowerManagerServiceClassInfo.goToSleepFromNative,
+ nanoseconds_to_milliseconds(eventTime), 0);
+ checkAndClearExceptionFromCallback(env, "goToSleepFromNative");
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+static void nativeInit(JNIEnv* env, jobject obj) {
+ gPowerManagerServiceObj = env->NewGlobalRef(obj);
+
+ status_t err = hw_get_module(POWER_HARDWARE_MODULE_ID,
+ (hw_module_t const**)&gPowerModule);
+ if (!err) {
+ gPowerModule->init(gPowerModule);
+ } else {
+ ALOGE("Couldn't load %s module (%s)", POWER_HARDWARE_MODULE_ID, strerror(-err));
+ }
+}
+
+static void nativeSetPowerState(JNIEnv* env,
+ jclass clazz, jboolean screenOn, jboolean screenBright) {
+ AutoMutex _l(gPowerManagerLock);
+ gScreenOn = screenOn;
+ gScreenBright = screenBright;
+}
+
+static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {
+ ScopedUtfChars name(env, nameStr);
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
+}
+
+static void nativeReleaseSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {
+ ScopedUtfChars name(env, nameStr);
+ release_wake_lock(name.c_str());
+}
+
+static void nativeSetInteractive(JNIEnv *env, jclass clazz, jboolean enable) {
+ if (gPowerModule) {
+ if (enable) {
+ ALOGD_IF_SLOW(20, "Excessive delay in setInteractive(true) while turning screen on");
+ gPowerModule->setInteractive(gPowerModule, true);
+ } else {
+ ALOGD_IF_SLOW(20, "Excessive delay in setInteractive(false) while turning screen off");
+ gPowerModule->setInteractive(gPowerModule, false);
+ }
+ }
+}
+
+static void nativeSetAutoSuspend(JNIEnv *env, jclass clazz, jboolean enable) {
+ if (enable) {
+ ALOGD_IF_SLOW(100, "Excessive delay in autosuspend_enable() while turning screen off");
+ autosuspend_enable();
+ } else {
+ ALOGD_IF_SLOW(100, "Excessive delay in autosuspend_disable() while turning screen on");
+ autosuspend_disable();
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+static JNINativeMethod gPowerManagerServiceMethods[] = {
+ /* name, signature, funcPtr */
+ { "nativeInit", "()V",
+ (void*) nativeInit },
+ { "nativeSetPowerState", "(ZZ)V",
+ (void*) nativeSetPowerState },
+ { "nativeAcquireSuspendBlocker", "(Ljava/lang/String;)V",
+ (void*) nativeAcquireSuspendBlocker },
+ { "nativeReleaseSuspendBlocker", "(Ljava/lang/String;)V",
+ (void*) nativeReleaseSuspendBlocker },
+ { "nativeSetInteractive", "(Z)V",
+ (void*) nativeSetInteractive },
+ { "nativeSetAutoSuspend", "(Z)V",
+ (void*) nativeSetAutoSuspend },
+};
+
+#define FIND_CLASS(var, className) \
+ var = env->FindClass(className); \
+ LOG_FATAL_IF(! var, "Unable to find class " className);
+
+#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+ var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find method " methodName);
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+ var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+int register_android_server_PowerManagerService(JNIEnv* env) {
+ int res = jniRegisterNativeMethods(env, "com/android/server/power/PowerManagerService",
+ gPowerManagerServiceMethods, NELEM(gPowerManagerServiceMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ // Callbacks
+
+ jclass clazz;
+ FIND_CLASS(clazz, "com/android/server/power/PowerManagerService");
+
+ GET_METHOD_ID(gPowerManagerServiceClassInfo.wakeUpFromNative, clazz,
+ "wakeUpFromNative", "(J)V");
+
+ GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleepFromNative, clazz,
+ "goToSleepFromNative", "(JI)V");
+
+ GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivityFromNative, clazz,
+ "userActivityFromNative", "(JII)V");
+
+ // Initialize
+ for (int i = 0; i <= USER_ACTIVITY_EVENT_LAST; i++) {
+ gLastEventTime[i] = LLONG_MIN;
+ }
+ gScreenOn = true;
+ gScreenBright = true;
+ gPowerManagerServiceObj = NULL;
+ gPowerModule = NULL;
+ return 0;
+}
+
+} /* namespace android */