diff options
| author | 2020-12-22 16:17:10 +0000 | |
|---|---|---|
| committer | 2020-12-22 16:17:10 +0000 | |
| commit | ba2a484b35d024e52d145fa6a5a71afa238e665f (patch) | |
| tree | dacac0731450c8fdd896d0719c9d6e3b387a1492 | |
| parent | 3c36c16ff629bccfee4561130785b613b90aa5ea (diff) | |
| parent | b5b0f5678e590c01a48e9f0cfdad62ed14d070fe (diff) | |
Merge changes I90ef1251,I0e93d5e7
* changes:
Add owners for power stats jni code
Add PowerStats HAL 1.0 support
9 files changed, 597 insertions, 31 deletions
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 083e970cc434..2f7c5234d982 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -254,9 +254,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(); final MeasuredEnergyArray initialEnergies = getEnergyConsumptionData(); final boolean[] supportedBuckets = getSupportedEnergyBuckets(initialEnergies); diff --git a/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java b/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java index 88e5f69e02c4..79c039291f57 100644 --- a/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java +++ b/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java @@ -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 { diff --git a/services/core/java/com/android/server/powerstats/PowerStatsService.java b/services/core/java/com/android/server/powerstats/PowerStatsService.java index 1150d4bbe770..ce50e5833c45 100644 --- a/services/core/java/com/android/server/powerstats/PowerStatsService.java +++ b/services/core/java/com/android/server/powerstats/PowerStatsService.java @@ -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. diff --git a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java index 5a4256ac0264..5e23b86e0adb 100644 --- a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java +++ b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java @@ -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 diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 2c4eb1b92086..77ca4e9eddab 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -40,6 +40,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", diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS index 7fc55656fc80..995cfe9fc2de 100644 --- a/services/core/jni/OWNERS +++ b/services/core/jni/OWNERS @@ -23,6 +23,7 @@ per-file com_android_server_locksettings_* = file:/services/core/java/com/androi per-file com_android_server_net_* = file:/services/core/java/com/android/server/net/OWNERS per-file com_android_server_pm_* = file:/services/core/java/com/android/server/pm/OWNERS per-file com_android_server_power_* = file:/services/core/java/com/android/server/power/OWNERS +per-file com_android_server_powerstats_* = file:/services/core/java/com/android/server/powerstats/OWNERS per-file com_android_server_se_* = file:/core/java/android/se/OWNERS per-file com_android_server_security_* = file:/core/java/android/security/OWNERS per-file com_android_server_tv_* = file:/media/java/android/media/tv/OWNERS diff --git a/services/core/jni/com_android_server_powerstats_PowerStatsService.cpp b/services/core/jni/com_android_server_powerstats_PowerStatsService.cpp new file mode 100644 index 000000000000..f5b851f7aea5 --- /dev/null +++ b/services/core/jni/com_android_server_powerstats_PowerStatsService.cpp @@ -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 diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index 5a0d08aeb6b3..85ef39470cb3 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -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); diff --git a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java index b26d1efef2a8..08d4caacd777 100644 --- a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java @@ -209,7 +209,7 @@ public class PowerStatsServiceTest { } @Override - public boolean initialize() { + public boolean isInitialized() { return true; } } |