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