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