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 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. 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 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 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. 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 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 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 176 static void nativeInit(JNIEnv* env, jobject obj) { 177 gPowerManagerServiceObj = env->NewGlobalRef(obj); 178 179 gPowerHalMutex.lock(); 180 connectPowerHalLocked(); 181 gPowerHalMutex.unlock(); 182 } 183 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 189 static void nativeReleaseSuspendBlocker(JNIEnv *env, jclass /* clazz */, jstring nameStr) { 190 ScopedUtfChars name(env, nameStr); 191 release_wake_lock(name.c_str()); 192 } 193 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 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 223 static void nativeSendPowerHint(JNIEnv* /* env */, jclass /* clazz */, jint hintId, jint data) { 224 sendPowerHint(static_cast<PowerHint>(hintId), data); 225 } 226 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 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