• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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