blob: ccd9bd0a50ca0bf3ada58050f12a9b2dcc14d373 [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define TAG "HintManagerService-JNI"
//#define LOG_NDEBUG 0
#include <aidl/android/hardware/power/IPower.h>
#include <android-base/stringprintf.h>
#include <inttypes.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedPrimitiveArray.h>
#include <powermanager/PowerHalController.h>
#include <utils/Log.h>
#include <unordered_map>
#include "jni.h"
using aidl::android::hardware::power::IPowerHintSession;
using aidl::android::hardware::power::SessionHint;
using aidl::android::hardware::power::SessionMode;
using aidl::android::hardware::power::WorkDuration;
using android::base::StringPrintf;
namespace android {
static struct {
jclass clazz{};
jfieldID workPeriodStartTimestampNanos{};
jfieldID actualTotalDurationNanos{};
jfieldID actualCpuDurationNanos{};
jfieldID actualGpuDurationNanos{};
jfieldID timestampNanos{};
} gWorkDurationInfo;
static power::PowerHalController gPowerHalController;
static std::unordered_map<jlong, std::shared_ptr<IPowerHintSession>> gSessionMap;
static std::mutex gSessionMapLock;
static int64_t getHintSessionPreferredRate() {
int64_t rate = -1;
auto result = gPowerHalController.getHintSessionPreferredRate();
if (result.isOk()) {
rate = result.value();
}
return rate;
}
static jlong createHintSession(JNIEnv* env, int32_t tgid, int32_t uid,
std::vector<int32_t> threadIds, int64_t durationNanos) {
auto result = gPowerHalController.createHintSession(tgid, uid, threadIds, durationNanos);
if (result.isOk()) {
auto session_ptr = reinterpret_cast<jlong>(result.value().get());
{
std::unique_lock<std::mutex> sessionLock(gSessionMapLock);
auto res = gSessionMap.insert({session_ptr, result.value()});
return res.second ? session_ptr : 0;
}
}
return 0;
}
static void pauseHintSession(JNIEnv* env, int64_t session_ptr) {
auto appSession = reinterpret_cast<IPowerHintSession*>(session_ptr);
appSession->pause();
}
static void resumeHintSession(JNIEnv* env, int64_t session_ptr) {
auto appSession = reinterpret_cast<IPowerHintSession*>(session_ptr);
appSession->resume();
}
static void closeHintSession(JNIEnv* env, int64_t session_ptr) {
auto appSession = reinterpret_cast<IPowerHintSession*>(session_ptr);
appSession->close();
std::unique_lock<std::mutex> sessionLock(gSessionMapLock);
gSessionMap.erase(session_ptr);
}
static void updateTargetWorkDuration(int64_t session_ptr, int64_t targetDurationNanos) {
auto appSession = reinterpret_cast<IPowerHintSession*>(session_ptr);
appSession->updateTargetWorkDuration(targetDurationNanos);
}
static void reportActualWorkDuration(int64_t session_ptr,
const std::vector<WorkDuration>& actualDurations) {
auto appSession = reinterpret_cast<IPowerHintSession*>(session_ptr);
appSession->reportActualWorkDuration(actualDurations);
}
static void sendHint(int64_t session_ptr, SessionHint hint) {
auto appSession = reinterpret_cast<IPowerHintSession*>(session_ptr);
appSession->sendHint(hint);
}
static void setThreads(int64_t session_ptr, const std::vector<int32_t>& threadIds) {
auto appSession = reinterpret_cast<IPowerHintSession*>(session_ptr);
appSession->setThreads(threadIds);
}
static void setMode(int64_t session_ptr, SessionMode mode, bool enabled) {
auto appSession = reinterpret_cast<IPowerHintSession*>(session_ptr);
appSession->setMode(mode, enabled);
}
// ----------------------------------------------------------------------------
static void nativeInit(JNIEnv* env, jobject obj) {
gPowerHalController.init();
}
static jlong nativeGetHintSessionPreferredRate(JNIEnv* /* env */, jclass /* clazz */) {
return static_cast<jlong>(getHintSessionPreferredRate());
}
static jlong nativeCreateHintSession(JNIEnv* env, jclass /* clazz */, jint tgid, jint uid,
jintArray tids, jlong durationNanos) {
ScopedIntArrayRO tidArray(env, tids);
if (nullptr == tidArray.get() || tidArray.size() == 0) {
ALOGW("GetIntArrayElements returns nullptr.");
return 0;
}
std::vector<int32_t> threadIds(tidArray.size());
for (size_t i = 0; i < tidArray.size(); i++) {
threadIds[i] = tidArray[i];
}
return createHintSession(env, tgid, uid, std::move(threadIds), durationNanos);
}
static void nativePauseHintSession(JNIEnv* env, jclass /* clazz */, jlong session_ptr) {
pauseHintSession(env, session_ptr);
}
static void nativeResumeHintSession(JNIEnv* env, jclass /* clazz */, jlong session_ptr) {
resumeHintSession(env, session_ptr);
}
static void nativeCloseHintSession(JNIEnv* env, jclass /* clazz */, jlong session_ptr) {
closeHintSession(env, session_ptr);
}
static void nativeUpdateTargetWorkDuration(JNIEnv* /* env */, jclass /* clazz */, jlong session_ptr,
jlong targetDurationNanos) {
updateTargetWorkDuration(session_ptr, targetDurationNanos);
}
static void nativeReportActualWorkDuration(JNIEnv* env, jclass /* clazz */, jlong session_ptr,
jlongArray actualDurations, jlongArray timeStamps) {
ScopedLongArrayRO arrayActualDurations(env, actualDurations);
ScopedLongArrayRO arrayTimeStamps(env, timeStamps);
std::vector<WorkDuration> actualList(arrayActualDurations.size());
for (size_t i = 0; i < arrayActualDurations.size(); i++) {
actualList[i].timeStampNanos = arrayTimeStamps[i];
actualList[i].durationNanos = arrayActualDurations[i];
}
reportActualWorkDuration(session_ptr, actualList);
}
static void nativeSendHint(JNIEnv* env, jclass /* clazz */, jlong session_ptr, jint hint) {
sendHint(session_ptr, static_cast<SessionHint>(hint));
}
static void nativeSetThreads(JNIEnv* env, jclass /* clazz */, jlong session_ptr, jintArray tids) {
ScopedIntArrayRO arrayThreadIds(env, tids);
std::vector<int32_t> threadIds(arrayThreadIds.size());
for (size_t i = 0; i < arrayThreadIds.size(); i++) {
threadIds[i] = arrayThreadIds[i];
}
setThreads(session_ptr, threadIds);
}
static void nativeSetMode(JNIEnv* env, jclass /* clazz */, jlong session_ptr, jint mode,
jboolean enabled) {
setMode(session_ptr, static_cast<SessionMode>(mode), enabled);
}
static void nativeReportActualWorkDuration2(JNIEnv* env, jclass /* clazz */, jlong session_ptr,
jobjectArray jWorkDurations) {
int size = env->GetArrayLength(jWorkDurations);
std::vector<WorkDuration> workDurations(size);
for (int i = 0; i < size; i++) {
jobject workDuration = env->GetObjectArrayElement(jWorkDurations, i);
workDurations[i].workPeriodStartTimestampNanos =
env->GetLongField(workDuration, gWorkDurationInfo.workPeriodStartTimestampNanos);
workDurations[i].durationNanos =
env->GetLongField(workDuration, gWorkDurationInfo.actualTotalDurationNanos);
workDurations[i].cpuDurationNanos =
env->GetLongField(workDuration, gWorkDurationInfo.actualCpuDurationNanos);
workDurations[i].gpuDurationNanos =
env->GetLongField(workDuration, gWorkDurationInfo.actualGpuDurationNanos);
workDurations[i].timeStampNanos =
env->GetLongField(workDuration, gWorkDurationInfo.timestampNanos);
}
reportActualWorkDuration(session_ptr, workDurations);
}
// ----------------------------------------------------------------------------
static const JNINativeMethod sHintManagerServiceMethods[] = {
/* name, signature, funcPtr */
{"nativeInit", "()V", (void*)nativeInit},
{"nativeGetHintSessionPreferredRate", "()J", (void*)nativeGetHintSessionPreferredRate},
{"nativeCreateHintSession", "(II[IJ)J", (void*)nativeCreateHintSession},
{"nativePauseHintSession", "(J)V", (void*)nativePauseHintSession},
{"nativeResumeHintSession", "(J)V", (void*)nativeResumeHintSession},
{"nativeCloseHintSession", "(J)V", (void*)nativeCloseHintSession},
{"nativeUpdateTargetWorkDuration", "(JJ)V", (void*)nativeUpdateTargetWorkDuration},
{"nativeReportActualWorkDuration", "(J[J[J)V", (void*)nativeReportActualWorkDuration},
{"nativeSendHint", "(JI)V", (void*)nativeSendHint},
{"nativeSetThreads", "(J[I)V", (void*)nativeSetThreads},
{"nativeSetMode", "(JIZ)V", (void*)nativeSetMode},
{"nativeReportActualWorkDuration", "(J[Landroid/os/WorkDuration;)V",
(void*)nativeReportActualWorkDuration2},
};
int register_android_server_HintManagerService(JNIEnv* env) {
gWorkDurationInfo.clazz = env->FindClass("android/os/WorkDuration");
gWorkDurationInfo.workPeriodStartTimestampNanos =
env->GetFieldID(gWorkDurationInfo.clazz, "mWorkPeriodStartTimestampNanos", "J");
gWorkDurationInfo.actualTotalDurationNanos =
env->GetFieldID(gWorkDurationInfo.clazz, "mActualTotalDurationNanos", "J");
gWorkDurationInfo.actualCpuDurationNanos =
env->GetFieldID(gWorkDurationInfo.clazz, "mActualCpuDurationNanos", "J");
gWorkDurationInfo.actualGpuDurationNanos =
env->GetFieldID(gWorkDurationInfo.clazz, "mActualGpuDurationNanos", "J");
gWorkDurationInfo.timestampNanos =
env->GetFieldID(gWorkDurationInfo.clazz, "mTimestampNanos", "J");
return jniRegisterNativeMethods(env,
"com/android/server/power/hint/"
"HintManagerService$NativeWrapper",
sHintManagerServiceMethods, NELEM(sHintManagerServiceMethods));
}
} /* namespace android */