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