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
checkAndClearExceptionFromCallback(JNIEnv * env,const char * methodName)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.
connectPowerHalLocked()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
getPowerHalV1_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
getPowerHalV1_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.
processPowerHalReturn(const Return<void> & ret,const char * functionName)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
sendPowerHint(PowerHint hintId,uint32_t data)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
android_server_PowerManagerService_userActivity(nsecs_t eventTime,int32_t eventType)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
nativeInit(JNIEnv * env,jobject obj)176 static void nativeInit(JNIEnv* env, jobject obj) {
177 gPowerManagerServiceObj = env->NewGlobalRef(obj);
178
179 gPowerHalMutex.lock();
180 connectPowerHalLocked();
181 gPowerHalMutex.unlock();
182 }
183
nativeAcquireSuspendBlocker(JNIEnv * env,jclass,jstring nameStr)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
nativeReleaseSuspendBlocker(JNIEnv * env,jclass,jstring nameStr)189 static void nativeReleaseSuspendBlocker(JNIEnv *env, jclass /* clazz */, jstring nameStr) {
190 ScopedUtfChars name(env, nameStr);
191 release_wake_lock(name.c_str());
192 }
193
nativeSetInteractive(JNIEnv *,jclass,jboolean enable)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
nativeSetAutoSuspend(JNIEnv *,jclass,jboolean enable)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
nativeSendPowerHint(JNIEnv *,jclass,jint hintId,jint data)223 static void nativeSendPowerHint(JNIEnv* /* env */, jclass /* clazz */, jint hintId, jint data) {
224 sendPowerHint(static_cast<PowerHint>(hintId), data);
225 }
226
nativeSetFeature(JNIEnv *,jclass,jint featureId,jint data)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
register_android_server_PowerManagerService(JNIEnv * env)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