Add PowerStats HAL 1.0 support

Bug: 173123066
Test: atest FrameworksServicesTests:PowerStatsServiceTest
Test: Tested across a range of existing devices with varying degrees of
PowerStats HAL 1.0/2.0 support and no support.

Change-Id: I0e93d5e718ebc1f4e8fa9422d480a3717593ea32
This commit is contained in:
Mat Bevilacqua
2020-11-17 16:21:16 -08:00
parent 22e6db8761
commit 0484a89b77
8 changed files with 596 additions and 31 deletions

View File

@@ -250,9 +250,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
mHandler = new Handler(mHandlerThread.getLooper());
// TODO(b/173077356): Replace directly calling the HAL with PowerStatsService queries
// Make sure to init Hal Wrapper before creating BatteryStatsImpl.
mPowerStatsHALWrapper = new PowerStatsHALWrapper.PowerStatsHALWrapperImpl();
mPowerStatsHALWrapper.initialize();
mPowerStatsHALWrapper = PowerStatsHALWrapper.getPowerStatsHalImpl();
mStats = new BatteryStatsImpl(systemDir, handler, this,
this, mUserManagerUserInfoProvider);

View File

@@ -16,7 +16,11 @@
package com.android.server.powerstats;
import android.hardware.power.stats.ChannelInfo;
import android.hardware.power.stats.EnergyMeasurement;
import android.hardware.power.stats.IPowerStats;
import android.hardware.power.stats.PowerEntityInfo;
import android.hardware.power.stats.StateResidencyResult;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
@@ -32,6 +36,7 @@ import java.util.function.Supplier;
*/
public final class PowerStatsHALWrapper {
private static final String TAG = PowerStatsHALWrapper.class.getSimpleName();
private static final boolean DEBUG = false;
/**
* IPowerStatsHALWrapper defines the interface to the PowerStatsHAL.
@@ -122,17 +127,30 @@ public final class PowerStatsHALWrapper {
*
* @return true if connection to power stats HAL was correctly established.
*/
boolean initialize();
boolean isInitialized();
}
/**
* PowerStatsHALWrapperImpl is the implementation of the IPowerStatsHALWrapper
* used by the PowerStatsService. Other implementations will be used by the testing
* framework and will be passed into the PowerStatsService through an injector.
* PowerStatsHALWrapper20Impl is the implementation of the IPowerStatsHALWrapper
* used by the PowerStatsService on devices that support only PowerStats HAL 2.0.
* Other implementations will be used by the testing framework and will be passed
* into the PowerStatsService through an injector.
*/
public static final class PowerStatsHALWrapperImpl implements IPowerStatsHALWrapper {
public static final class PowerStatsHAL20WrapperImpl implements IPowerStatsHALWrapper {
private static Supplier<IPowerStats> sVintfPowerStats;
public PowerStatsHAL20WrapperImpl() {
Supplier<IPowerStats> service = new VintfHalCache();
sVintfPowerStats = null;
if (service.get() == null) {
if (DEBUG) Slog.d(TAG, "PowerStats HAL 2.0 not available on this device.");
sVintfPowerStats = null;
} else {
sVintfPowerStats = service;
}
}
@Override
public android.hardware.power.stats.PowerEntityInfo[] getPowerEntityInfo() {
android.hardware.power.stats.PowerEntityInfo[] powerEntityInfoHAL = null;
@@ -141,7 +159,7 @@ public final class PowerStatsHALWrapper {
try {
powerEntityInfoHAL = sVintfPowerStats.get().getPowerEntityInfo();
} catch (RemoteException e) {
Slog.e(TAG, "Failed to get power entity info from PowerStats HAL");
if (DEBUG) Slog.d(TAG, "Failed to get power entity info from PowerStats HAL");
}
}
@@ -158,7 +176,7 @@ public final class PowerStatsHALWrapper {
stateResidencyResultHAL =
sVintfPowerStats.get().getStateResidency(powerEntityIds);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to get state residency from PowerStats HAL");
if (DEBUG) Slog.d(TAG, "Failed to get state residency from PowerStats HAL");
}
}
@@ -173,7 +191,9 @@ public final class PowerStatsHALWrapper {
try {
energyConsumerInfoHAL = sVintfPowerStats.get().getEnergyConsumerInfo();
} catch (RemoteException e) {
Slog.e(TAG, "Failed to get energy consumer info from PowerStats HAL");
if (DEBUG) {
Slog.d(TAG, "Failed to get energy consumer info from PowerStats HAL");
}
}
}
@@ -190,7 +210,9 @@ public final class PowerStatsHALWrapper {
energyConsumedHAL =
sVintfPowerStats.get().getEnergyConsumed(energyConsumerIds);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to get energy consumer results from PowerStats HAL");
if (DEBUG) {
Slog.d(TAG, "Failed to get energy consumer results from PowerStats HAL");
}
}
}
@@ -205,7 +227,7 @@ public final class PowerStatsHALWrapper {
try {
energyMeterInfoHAL = sVintfPowerStats.get().getEnergyMeterInfo();
} catch (RemoteException e) {
Slog.e(TAG, "Failed to get energy meter info from PowerStats HAL");
if (DEBUG) Slog.d(TAG, "Failed to get energy meter info from PowerStats HAL");
}
}
@@ -221,7 +243,7 @@ public final class PowerStatsHALWrapper {
energyMeasurementHAL =
sVintfPowerStats.get().readEnergyMeters(channelIds);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to get energy measurements from PowerStats HAL");
if (DEBUG) Slog.d(TAG, "Failed to get energy measurements from PowerStats HAL");
}
}
@@ -229,17 +251,90 @@ public final class PowerStatsHALWrapper {
}
@Override
public boolean initialize() {
Supplier<IPowerStats> service = new VintfHalCache();
public boolean isInitialized() {
return (sVintfPowerStats != null);
}
}
if (service.get() == null) {
sVintfPowerStats = null;
return false;
/**
* PowerStatsHALWrapper10Impl is the implementation of the IPowerStatsHALWrapper
* used by the PowerStatsService on devices that support only PowerStats HAL 1.0.
* Other implementations will be used by the testing framework and will be passed
* into the PowerStatsService through an injector.
*/
public static final class PowerStatsHAL10WrapperImpl implements IPowerStatsHALWrapper {
private boolean mIsInitialized;
// PowerStatsHAL 1.0 native functions exposed by JNI layer.
private static native boolean nativeInit();
private static native PowerEntityInfo[] nativeGetPowerEntityInfo();
private static native StateResidencyResult[] nativeGetStateResidency(int[] powerEntityIds);
private static native ChannelInfo[] nativeGetEnergyMeterInfo();
private static native EnergyMeasurement[] nativeReadEnergyMeters(int[] channelIds);
public PowerStatsHAL10WrapperImpl() {
if (nativeInit()) {
mIsInitialized = true;
} else {
sVintfPowerStats = service;
return true;
if (DEBUG) Slog.d(TAG, "PowerStats HAL 1.0 not available on this device.");
mIsInitialized = false;
}
}
@Override
public android.hardware.power.stats.PowerEntityInfo[] getPowerEntityInfo() {
return nativeGetPowerEntityInfo();
}
@Override
public android.hardware.power.stats.StateResidencyResult[] getStateResidency(
int[] powerEntityIds) {
return nativeGetStateResidency(powerEntityIds);
}
@Override
public int[] getEnergyConsumerInfo() {
if (DEBUG) Slog.d(TAG, "Energy consumer info is not supported");
return null;
}
@Override
public android.hardware.power.stats.EnergyConsumerResult[] getEnergyConsumed(
int[] energyConsumerIds) {
if (DEBUG) Slog.d(TAG, "Energy consumer results are not supported");
return null;
}
@Override
public android.hardware.power.stats.ChannelInfo[] getEnergyMeterInfo() {
return nativeGetEnergyMeterInfo();
}
@Override
public android.hardware.power.stats.EnergyMeasurement[] readEnergyMeters(int[] channelIds) {
return nativeReadEnergyMeters(channelIds);
}
@Override
public boolean isInitialized() {
return mIsInitialized;
}
}
/**
* Returns an instance of an IPowerStatsHALWrapper. If PowerStats HAL 2.0 is supported on the
* device, return a PowerStatsHAL20WrapperImpl, else return a PowerStatsHAL10WrapperImpl.
*
* @return an instance of an IPowerStatsHALWrapper where preference is given to PowerStats HAL
* 2.0.
*/
public static IPowerStatsHALWrapper getPowerStatsHalImpl() {
PowerStatsHAL20WrapperImpl powerStatsHAL20WrapperImpl = new PowerStatsHAL20WrapperImpl();
if (powerStatsHAL20WrapperImpl.isInitialized()) {
return powerStatsHAL20WrapperImpl;
} else {
return new PowerStatsHAL10WrapperImpl();
}
}
private static class VintfHalCache implements Supplier<IPowerStats>, IBinder.DeathRecipient {

View File

@@ -29,7 +29,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.server.SystemService;
import com.android.server.powerstats.PowerStatsHALWrapper.IPowerStatsHALWrapper;
import com.android.server.powerstats.PowerStatsHALWrapper.PowerStatsHALWrapperImpl;
import com.android.server.powerstats.ProtoStreamUtils.ChannelInfoUtils;
import com.android.server.powerstats.ProtoStreamUtils.EnergyConsumerIdUtils;
import com.android.server.powerstats.ProtoStreamUtils.PowerEntityInfoUtils;
@@ -78,7 +77,7 @@ public class PowerStatsService extends SystemService {
}
IPowerStatsHALWrapper createPowerStatsHALWrapperImpl() {
return new PowerStatsHALWrapperImpl();
return PowerStatsHALWrapper.getPowerStatsHalImpl();
}
PowerStatsLogger createPowerStatsLogger(Context context, File dataStoragePath,
@@ -143,7 +142,7 @@ public class PowerStatsService extends SystemService {
private void onSystemServiceReady() {
mPowerStatsHALWrapper = mInjector.createPowerStatsHALWrapperImpl();
if (mPowerStatsHALWrapper.initialize()) {
if (mPowerStatsHALWrapper.isInitialized()) {
if (DEBUG) Slog.d(TAG, "Starting PowerStatsService");
// Only start logger and triggers if initialization is successful.

View File

@@ -46,23 +46,31 @@ public class ProtoStreamUtils {
static class PowerEntityInfoUtils {
public static void print(PowerEntityInfo[] powerEntityInfo) {
if (powerEntityInfo == null) return;
for (int i = 0; i < powerEntityInfo.length; i++) {
Slog.d(TAG, "PowerEntityId: " + powerEntityInfo[i].powerEntityId
+ ", PowerEntityName: " + powerEntityInfo[i].powerEntityName);
for (int j = 0; j < powerEntityInfo[i].states.length; j++) {
Slog.d(TAG, " StateId: " + powerEntityInfo[i].states[j].stateId
+ ", StateName: " + powerEntityInfo[i].states[j].stateName);
if (powerEntityInfo[i].states != null) {
for (int j = 0; j < powerEntityInfo[i].states.length; j++) {
Slog.d(TAG, " StateId: " + powerEntityInfo[i].states[j].stateId
+ ", StateName: " + powerEntityInfo[i].states[j].stateName);
}
}
}
}
public static void dumpsys(PowerEntityInfo[] powerEntityInfo, PrintWriter pw) {
if (powerEntityInfo == null) return;
for (int i = 0; i < powerEntityInfo.length; i++) {
pw.println("PowerEntityId: " + powerEntityInfo[i].powerEntityId
+ ", PowerEntityName: " + powerEntityInfo[i].powerEntityName);
for (int j = 0; j < powerEntityInfo[i].states.length; j++) {
pw.println(" StateId: " + powerEntityInfo[i].states[j].stateId
+ ", StateName: " + powerEntityInfo[i].states[j].stateName);
if (powerEntityInfo[i].states != null) {
for (int j = 0; j < powerEntityInfo[i].states.length; j++) {
pw.println(" StateId: " + powerEntityInfo[i].states[j].stateId
+ ", StateName: " + powerEntityInfo[i].states[j].stateName);
}
}
}
}
@@ -70,6 +78,8 @@ public class ProtoStreamUtils {
static class StateResidencyResultUtils {
public static void print(StateResidencyResult[] stateResidencyResult) {
if (stateResidencyResult == null) return;
for (int i = 0; i < stateResidencyResult.length; i++) {
Slog.d(TAG, "PowerEntityId: " + stateResidencyResult[i].powerEntityId);
for (int j = 0; j < stateResidencyResult[i].stateResidencyData.length; j++) {
@@ -90,6 +100,8 @@ public class ProtoStreamUtils {
public static void packProtoMessage(ChannelInfo[] channelInfo, ProtoOutputStream pos) {
long token;
if (channelInfo == null) return;
for (int i = 0; i < channelInfo.length; i++) {
token = pos.start(PowerStatsServiceMeterProto.CHANNEL_INFO);
pos.write(ChannelInfoProto.CHANNEL_ID, channelInfo[i].channelId);
@@ -100,6 +112,8 @@ public class ProtoStreamUtils {
}
public static void print(ChannelInfo[] channelInfo) {
if (channelInfo == null) return;
for (int i = 0; i < channelInfo.length; i++) {
Slog.d(TAG, "ChannelId: " + channelInfo[i].channelId
+ ", ChannelName: " + channelInfo[i].channelName);
@@ -107,6 +121,8 @@ public class ProtoStreamUtils {
}
public static void dumpsys(ChannelInfo[] channelInfo, PrintWriter pw) {
if (channelInfo == null) return;
for (int i = 0; i < channelInfo.length; i++) {
pw.println("ChannelId: " + channelInfo[i].channelId
+ ", ChannelName: " + channelInfo[i].channelName);
@@ -125,6 +141,8 @@ public class ProtoStreamUtils {
ProtoOutputStream pos) {
long token;
if (energyMeasurement == null) return;
for (int i = 0; i < energyMeasurement.length; i++) {
token = pos.start(PowerStatsServiceMeterProto.ENERGY_MEASUREMENT);
pos.write(EnergyMeasurementProto.CHANNEL_ID, energyMeasurement[i].channelId);
@@ -200,6 +218,8 @@ public class ProtoStreamUtils {
}
public static void print(EnergyMeasurement[] energyMeasurement) {
if (energyMeasurement == null) return;
for (int i = 0; i < energyMeasurement.length; i++) {
Slog.d(TAG, "ChannelId: " + energyMeasurement[i].channelId
+ ", Timestamp (ms): " + energyMeasurement[i].timestampMs
@@ -212,6 +232,8 @@ public class ProtoStreamUtils {
public static void packProtoMessage(int[] energyConsumerId, ProtoOutputStream pos) {
long token;
if (energyConsumerId == null) return;
for (int i = 0; i < energyConsumerId.length; i++) {
token = pos.start(PowerStatsServiceModelProto.ENERGY_CONSUMER_ID);
pos.write(EnergyConsumerIdProto.ENERGY_CONSUMER_ID, energyConsumerId[i]);
@@ -220,12 +242,16 @@ public class ProtoStreamUtils {
}
public static void print(int[] energyConsumerId) {
if (energyConsumerId == null) return;
for (int i = 0; i < energyConsumerId.length; i++) {
Slog.d(TAG, "EnergyConsumerId: " + energyConsumerId[i]);
}
}
public static void dumpsys(int[] energyConsumerId, PrintWriter pw) {
if (energyConsumerId == null) return;
for (int i = 0; i < energyConsumerId.length; i++) {
pw.println("EnergyConsumerId: " + energyConsumerId[i]);
}
@@ -243,6 +269,8 @@ public class ProtoStreamUtils {
ProtoOutputStream pos) {
long token;
if (energyConsumerResult == null) return;
for (int i = 0; i < energyConsumerResult.length; i++) {
token = pos.start(PowerStatsServiceModelProto.ENERGY_CONSUMER_RESULT);
pos.write(EnergyConsumerResultProto.ENERGY_CONSUMER_ID,
@@ -321,6 +349,8 @@ public class ProtoStreamUtils {
}
public static void print(EnergyConsumerResult[] energyConsumerResult) {
if (energyConsumerResult == null) return;
for (int i = 0; i < energyConsumerResult.length; i++) {
Slog.d(TAG, "EnergyConsumerId: " + energyConsumerResult[i].energyConsumerId
+ ", Timestamp (ms): " + energyConsumerResult[i].timestampMs

View File

@@ -37,6 +37,7 @@ cc_library_static {
"com_android_server_locksettings_SyntheticPasswordManager.cpp",
"com_android_server_net_NetworkStatsService.cpp",
"com_android_server_power_PowerManagerService.cpp",
"com_android_server_powerstats_PowerStatsService.cpp",
"com_android_server_security_VerityUtils.cpp",
"com_android_server_SerialService.cpp",
"com_android_server_soundtrigger_middleware_AudioSessionProviderImpl.cpp",

View File

@@ -0,0 +1,440 @@
/*
* Copyright (C) 2020 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 LOG_TAG "PowerStatsService"
#include <android/hardware/power/stats/1.0/IPowerStats.h>
#include <jni.h>
#include <nativehelper/JNIHelp.h>
#include <log/log.h>
using android::hardware::hidl_vec;
using android::hardware::Return;
using android::hardware::power::stats::V1_0::EnergyData;
using android::hardware::power::stats::V1_0::RailInfo;
using android::hardware::power::stats::V1_0::Status;
// ChannelInfo
static jclass class_CI;
static jmethodID method_CI_init;
static jfieldID field_CI_channelId;
static jfieldID field_CI_channelName;
// EnergyMeasurement
static jclass class_EM;
static jmethodID method_EM_init;
static jfieldID field_EM_channelId;
static jfieldID field_EM_timestampMs;
static jfieldID field_EM_durationMs;
static jfieldID field_EM_energyUWs;
// StateInfo
static jclass class_SI;
static jmethodID method_SI_init;
static jfieldID field_SI_stateId;
static jfieldID field_SI_stateName;
// PowerEntityInfo
static jclass class_PEI;
static jmethodID method_PEI_init;
static jfieldID field_PEI_powerEntityId;
static jfieldID field_PEI_powerEntityName;
static jfieldID field_PEI_states;
// StateResidency
static jclass class_SR;
static jmethodID method_SR_init;
static jfieldID field_SR_stateId;
static jfieldID field_SR_totalTimeInStateMs;
static jfieldID field_SR_totalStateEntryCount;
static jfieldID field_SR_lastEntryTimestampMs;
// StateResidencyResult
static jclass class_SRR;
static jmethodID method_SRR_init;
static jfieldID field_SRR_powerEntityId;
static jfieldID field_SRR_stateResidencyData;
namespace android {
static std::mutex gPowerStatsHalMutex;
static sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHalV1_0_ptr = nullptr;
static void deinitPowerStats() {
gPowerStatsHalV1_0_ptr = nullptr;
}
struct PowerStatsHalDeathRecipient : virtual public hardware::hidl_death_recipient {
virtual void serviceDied(uint64_t cookie,
const wp<android::hidl::base::V1_0::IBase> &who) override {
// The HAL just died. Reset all handles to HAL services.
std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
deinitPowerStats();
}
};
sp<PowerStatsHalDeathRecipient> gPowerStatsHalDeathRecipient = new PowerStatsHalDeathRecipient();
static bool connectToPowerStatsHal() {
if (gPowerStatsHalV1_0_ptr == nullptr) {
gPowerStatsHalV1_0_ptr = android::hardware::power::stats::V1_0::IPowerStats::getService();
if (gPowerStatsHalV1_0_ptr == nullptr) {
ALOGE("Unable to get power.stats HAL service.");
return false;
}
// Link death recipient to power.stats service handle
hardware::Return<bool> linked =
gPowerStatsHalV1_0_ptr->linkToDeath(gPowerStatsHalDeathRecipient, 0);
if (!linked.isOk()) {
ALOGE("Transaction error in linking to power.stats HAL death: %s",
linked.description().c_str());
deinitPowerStats();
return false;
} else if (!linked) {
ALOGW("Unable to link to power.stats HAL death notifications");
return false;
}
}
return true;
}
static bool checkResult(const Return<void> &ret, const char *function) {
if (!ret.isOk()) {
ALOGE("%s failed: requested HAL service not available. Description: %s", function,
ret.description().c_str());
if (ret.isDeadObject()) {
deinitPowerStats();
}
return false;
}
return true;
}
static jobjectArray nativeGetPowerEntityInfo(JNIEnv *env, jclass clazz) {
std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
if (!connectToPowerStatsHal()) {
ALOGE("nativeGetPowerEntityInfo failed to connect to power.stats HAL");
return nullptr;
}
jobjectArray powerEntityInfoArray = nullptr;
Return<void> ret = gPowerStatsHalV1_0_ptr->getPowerEntityInfo(
[&env, &powerEntityInfoArray](auto infos, auto status) {
if (status != Status::SUCCESS) {
ALOGE("Error getting power entity info");
} else {
powerEntityInfoArray = env->NewObjectArray(infos.size(), class_PEI, nullptr);
for (int i = 0; i < infos.size(); i++) {
jstring powerEntityName =
env->NewStringUTF(infos[i].powerEntityName.c_str());
jobject powerEntityInfo = env->NewObject(class_PEI, method_PEI_init);
env->SetIntField(powerEntityInfo, field_PEI_powerEntityId,
infos[i].powerEntityId);
env->SetObjectField(powerEntityInfo, field_PEI_powerEntityName,
powerEntityName);
env->SetObjectArrayElement(powerEntityInfoArray, i, powerEntityInfo);
env->DeleteLocalRef(powerEntityName);
env->DeleteLocalRef(powerEntityInfo);
}
}
});
if (!checkResult(ret, __func__)) {
return nullptr;
}
ret = gPowerStatsHalV1_0_ptr->getPowerEntityStateInfo(
{}, [&env, &powerEntityInfoArray](auto infos, auto status) {
if (status != Status::SUCCESS) {
ALOGE("Error getting power entity state info");
} else {
for (int i = 0; i < infos.size(); i++) {
jobjectArray stateInfoArray =
env->NewObjectArray(infos[i].states.size(), class_SI, nullptr);
for (int j = 0; j < infos[i].states.size(); j++) {
jstring powerEntityStateName = env->NewStringUTF(
infos[i].states[j].powerEntityStateName.c_str());
jobject stateInfo = env->NewObject(class_SI, method_SI_init);
env->SetIntField(stateInfo, field_SI_stateId,
infos[i].states[j].powerEntityStateId);
env->SetObjectField(stateInfo, field_SI_stateName,
powerEntityStateName);
env->SetObjectArrayElement(stateInfoArray, j, stateInfo);
env->DeleteLocalRef(powerEntityStateName);
env->DeleteLocalRef(stateInfo);
}
for (int j = 0; j < env->GetArrayLength(powerEntityInfoArray); j++) {
jobject powerEntityInfo =
env->GetObjectArrayElement(powerEntityInfoArray, j);
if (env->GetIntField(powerEntityInfo, field_PEI_powerEntityId) ==
infos[i].powerEntityId) {
env->SetObjectField(powerEntityInfo, field_PEI_states,
stateInfoArray);
env->SetObjectArrayElement(powerEntityInfoArray, j,
powerEntityInfo);
break;
}
}
}
}
});
if (!checkResult(ret, __func__)) {
return nullptr;
}
return powerEntityInfoArray;
}
static jobjectArray nativeGetStateResidency(JNIEnv *env, jclass clazz, jintArray powerEntityIds) {
std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
if (!connectToPowerStatsHal()) {
ALOGE("nativeGetStateResidency failed to connect to power.stats HAL");
return nullptr;
}
size_t powerEntityIdCount = env->GetArrayLength(powerEntityIds);
hidl_vec<uint32_t> powerEntityIdVector(powerEntityIdCount);
jint *powerEntityIdElements = env->GetIntArrayElements(powerEntityIds, 0);
for (int i = 0; i < powerEntityIdCount; i++) {
powerEntityIdVector[i] = powerEntityIdElements[i];
}
env->ReleaseIntArrayElements(powerEntityIds, powerEntityIdElements, 0);
jobjectArray stateResidencyResultArray = nullptr;
Return<void> ret = gPowerStatsHalV1_0_ptr->getPowerEntityStateResidencyData(
powerEntityIdVector, [&env, &stateResidencyResultArray](auto results, auto status) {
if (status != Status::SUCCESS) {
ALOGE("Error getting power entity state residency data");
} else {
stateResidencyResultArray =
env->NewObjectArray(results.size(), class_SRR, nullptr);
for (int i = 0; i < results.size(); i++) {
jobjectArray stateResidencyArray =
env->NewObjectArray(results[i].stateResidencyData.size(), class_SR,
nullptr);
for (int j = 0; j < results[i].stateResidencyData.size(); j++) {
jobject stateResidency = env->NewObject(class_SR, method_SR_init);
env->SetIntField(stateResidency, field_SR_stateId,
results[i].stateResidencyData[j].powerEntityStateId);
env->SetLongField(stateResidency, field_SR_totalTimeInStateMs,
results[i].stateResidencyData[j].totalTimeInStateMs);
env->SetLongField(stateResidency, field_SR_totalStateEntryCount,
results[i]
.stateResidencyData[j]
.totalStateEntryCount);
env->SetLongField(stateResidency, field_SR_lastEntryTimestampMs,
results[i]
.stateResidencyData[j]
.lastEntryTimestampMs);
env->SetObjectArrayElement(stateResidencyArray, j, stateResidency);
env->DeleteLocalRef(stateResidency);
}
jobject stateResidencyResult = env->NewObject(class_SRR, method_SRR_init);
env->SetIntField(stateResidencyResult, field_SRR_powerEntityId,
results[i].powerEntityId);
env->SetObjectField(stateResidencyResult, field_SRR_stateResidencyData,
stateResidencyArray);
env->SetObjectArrayElement(stateResidencyResultArray, i,
stateResidencyResult);
env->DeleteLocalRef(stateResidencyResult);
}
}
});
if (!checkResult(ret, __func__)) {
return nullptr;
}
return stateResidencyResultArray;
}
static jobjectArray nativeGetEnergyMeterInfo(JNIEnv *env, jclass clazz) {
std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
if (!connectToPowerStatsHal()) {
ALOGE("nativeGetEnergyMeterInfo failed to connect to power.stats HAL");
return nullptr;
}
jobjectArray channelInfoArray = nullptr;
Return<void> ret = gPowerStatsHalV1_0_ptr->getRailInfo(
[&env, &channelInfoArray](auto railInfo, auto status) {
if (status != Status::SUCCESS) {
ALOGW("Error getting rail info");
} else {
channelInfoArray = env->NewObjectArray(railInfo.size(), class_CI, nullptr);
for (int i = 0; i < railInfo.size(); i++) {
jstring channelName = env->NewStringUTF(railInfo[i].railName.c_str());
jobject channelInfo = env->NewObject(class_CI, method_CI_init);
env->SetIntField(channelInfo, field_CI_channelId, railInfo[i].index);
env->SetObjectField(channelInfo, field_CI_channelName, channelName);
env->SetObjectArrayElement(channelInfoArray, i, channelInfo);
env->DeleteLocalRef(channelName);
env->DeleteLocalRef(channelInfo);
}
}
});
if (!checkResult(ret, __func__)) {
ALOGE("getRailInfo failed");
return nullptr;
}
return channelInfoArray;
}
static jobjectArray nativeReadEnergyMeters(JNIEnv *env, jclass clazz, jintArray channelIds) {
std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
if (!connectToPowerStatsHal()) {
ALOGE("nativeGetEnergy failed to connect to power.stats HAL");
}
size_t channelIdCount = env->GetArrayLength(channelIds);
hidl_vec<uint32_t> channelIdVector(channelIdCount);
jint *channelIdElements = env->GetIntArrayElements(channelIds, 0);
for (int i = 0; i < channelIdCount; i++) {
channelIdVector[i] = channelIdElements[i];
}
env->ReleaseIntArrayElements(channelIds, channelIdElements, 0);
jobjectArray energyMeasurementArray = nullptr;
Return<void> ret =
gPowerStatsHalV1_0_ptr
->getEnergyData(channelIdVector,
[&env, &energyMeasurementArray](auto energyData, auto status) {
if (status != Status::SUCCESS) {
ALOGW("Error getting energy data");
} else {
energyMeasurementArray =
env->NewObjectArray(energyData.size(), class_EM,
nullptr);
for (int i = 0; i < energyData.size(); i++) {
jobject energyMeasurement =
env->NewObject(class_EM, method_EM_init);
env->SetIntField(energyMeasurement,
field_EM_channelId,
energyData[i].index);
env->SetLongField(energyMeasurement,
field_EM_timestampMs,
energyData[i].timestamp);
env->SetLongField(energyMeasurement,
field_EM_durationMs, -1);
env->SetLongField(energyMeasurement,
field_EM_energyUWs,
energyData[i].energy);
env->SetObjectArrayElement(energyMeasurementArray,
i, energyMeasurement);
env->DeleteLocalRef(energyMeasurement);
}
}
});
if (!checkResult(ret, __func__)) {
ALOGE("getEnergyData failed");
return nullptr;
}
return energyMeasurementArray;
}
static jboolean nativeInit(JNIEnv *env, jclass clazz) {
std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
// ChannelInfo
jclass temp = env->FindClass("android/hardware/power/stats/ChannelInfo");
class_CI = (jclass)env->NewGlobalRef(temp);
method_CI_init = env->GetMethodID(class_CI, "<init>", "()V");
field_CI_channelId = env->GetFieldID(class_CI, "channelId", "I");
field_CI_channelName = env->GetFieldID(class_CI, "channelName", "Ljava/lang/String;");
// EnergyMeasurement
temp = env->FindClass("android/hardware/power/stats/EnergyMeasurement");
class_EM = (jclass)env->NewGlobalRef(temp);
method_EM_init = env->GetMethodID(class_EM, "<init>", "()V");
field_EM_channelId = env->GetFieldID(class_EM, "channelId", "I");
field_EM_timestampMs = env->GetFieldID(class_EM, "timestampMs", "J");
field_EM_durationMs = env->GetFieldID(class_EM, "durationMs", "J");
field_EM_energyUWs = env->GetFieldID(class_EM, "energyUWs", "J");
// StateInfo
temp = env->FindClass("android/hardware/power/stats/StateInfo");
class_SI = (jclass)env->NewGlobalRef(temp);
method_SI_init = env->GetMethodID(class_SI, "<init>", "()V");
field_SI_stateId = env->GetFieldID(class_SI, "stateId", "I");
field_SI_stateName = env->GetFieldID(class_SI, "stateName", "Ljava/lang/String;");
// PowerEntityInfo
temp = env->FindClass("android/hardware/power/stats/PowerEntityInfo");
class_PEI = (jclass)env->NewGlobalRef(temp);
method_PEI_init = env->GetMethodID(class_PEI, "<init>", "()V");
field_PEI_powerEntityId = env->GetFieldID(class_PEI, "powerEntityId", "I");
field_PEI_powerEntityName = env->GetFieldID(class_PEI, "powerEntityName", "Ljava/lang/String;");
field_PEI_states =
env->GetFieldID(class_PEI, "states", "[Landroid/hardware/power/stats/StateInfo;");
// StateResidency
temp = env->FindClass("android/hardware/power/stats/StateResidency");
class_SR = (jclass)env->NewGlobalRef(temp);
method_SR_init = env->GetMethodID(class_SR, "<init>", "()V");
field_SR_stateId = env->GetFieldID(class_SR, "stateId", "I");
field_SR_totalTimeInStateMs = env->GetFieldID(class_SR, "totalTimeInStateMs", "J");
field_SR_totalStateEntryCount = env->GetFieldID(class_SR, "totalStateEntryCount", "J");
field_SR_lastEntryTimestampMs = env->GetFieldID(class_SR, "lastEntryTimestampMs", "J");
// StateResidencyResult
temp = env->FindClass("android/hardware/power/stats/StateResidencyResult");
class_SRR = (jclass)env->NewGlobalRef(temp);
method_SRR_init = env->GetMethodID(class_SRR, "<init>", "()V");
field_SRR_powerEntityId = env->GetFieldID(class_SRR, "powerEntityId", "I");
field_SRR_stateResidencyData =
env->GetFieldID(class_SRR, "stateResidencyData",
"[Landroid/hardware/power/stats/StateResidency;");
if (!connectToPowerStatsHal()) {
ALOGE("nativeInit failed to connect to power.stats HAL");
return false;
}
return true;
}
static const JNINativeMethod method_table[] = {
{"nativeInit", "()Z", (void *)nativeInit},
{"nativeGetPowerEntityInfo", "()[Landroid/hardware/power/stats/PowerEntityInfo;",
(void *)nativeGetPowerEntityInfo},
{"nativeGetStateResidency", "([I)[Landroid/hardware/power/stats/StateResidencyResult;",
(void *)nativeGetStateResidency},
{"nativeGetEnergyMeterInfo", "()[Landroid/hardware/power/stats/ChannelInfo;",
(void *)nativeGetEnergyMeterInfo},
{"nativeReadEnergyMeters", "([I)[Landroid/hardware/power/stats/EnergyMeasurement;",
(void *)nativeReadEnergyMeters},
};
int register_android_server_PowerStatsService(JNIEnv *env) {
return jniRegisterNativeMethods(env,
"com/android/server/powerstats/"
"PowerStatsHALWrapper$PowerStatsHAL10WrapperImpl",
method_table, NELEM(method_table));
}
}; // namespace android

View File

@@ -29,6 +29,7 @@ int register_android_server_ConsumerIrService(JNIEnv *env);
int register_android_server_InputManager(JNIEnv* env);
int register_android_server_LightsService(JNIEnv* env);
int register_android_server_PowerManagerService(JNIEnv* env);
int register_android_server_PowerStatsService(JNIEnv* env);
int register_android_server_storage_AppFuse(JNIEnv* env);
int register_android_server_SerialService(JNIEnv* env);
int register_android_server_SystemServer(JNIEnv* env);
@@ -82,6 +83,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
register_android_server_broadcastradio_BroadcastRadioService(env);
register_android_server_broadcastradio_Tuner(vm, env);
register_android_server_PowerManagerService(env);
register_android_server_PowerStatsService(env);
register_android_server_SerialService(env);
register_android_server_InputManager(env);
register_android_server_LightsService(env);

View File

@@ -209,7 +209,7 @@ public class PowerStatsServiceTest {
}
@Override
public boolean initialize() {
public boolean isInitialized() {
return true;
}
}