Files
device_google_wahoo/power-libperfmgr/Power.cpp
Wei Wang 15fd9f5fae Power: restart PowerHAL if audio HAL died with active low_latency hint
Audio low latency which can go parallel with other long-term hints and
there is small change that leaves the powerHAL stuck with the hint for
long time. This CL will require another property to record the state of it.

Bug: 67648152
Test: kill audiohal, audioserver
Change-Id: Ic0017b0c7a27994e7583d7701665b2cd156ca192
2018-01-16 14:02:32 -08:00

450 lines
17 KiB
C++

/*
* Copyright (C) 2018 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 ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
#define LOG_TAG "android.hardware.power@1.2-service.wahoo-libperfmgr"
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <utils/Log.h>
#include <utils/Trace.h>
#include "Power.h"
#include "power-helper.h"
/* RPM runs at 19.2Mhz. Divide by 19200 for msec */
#define RPM_CLK 19200
extern struct stat_pair rpm_stat_map[];
namespace android {
namespace hardware {
namespace power {
namespace V1_2 {
namespace implementation {
using ::android::hardware::power::V1_0::Feature;
using ::android::hardware::power::V1_0::PowerStatePlatformSleepState;
using ::android::hardware::power::V1_0::Status;
using ::android::hardware::power::V1_1::PowerStateSubsystem;
using ::android::hardware::power::V1_1::PowerStateSubsystemSleepState;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
Power::Power() :
mHintManager(HintManager::GetFromJSON("/vendor/etc/powerhint.json")),
mInteractionHandler(mHintManager),
mVRModeOn(false),
mSustainedPerfModeOn(false),
mEncoderModeOn(false) {
mInteractionHandler.Init();
std::string state = android::base::GetProperty(kPowerHalStateProp, "");
if (state == "VIDEO_ENCODE") {
ALOGI("Initialize with VIDEO_ENCODE on");
mHintManager->DoHint("VIDEO_ENCODE");
mEncoderModeOn = true;
} else if (state == "SUSTAINED_PERFORMANCE") {
ALOGI("Initialize with SUSTAINED_PERFORMANCE on");
mHintManager->DoHint("SUSTAINED_PERFORMANCE");
mSustainedPerfModeOn = true;
} else if (state == "VR_MODE") {
ALOGI("Initialize with VR_MODE on");
mHintManager->DoHint("VR_MODE");
mVRModeOn = true;
} else if (state == "VR_SUSTAINED_PERFORMANCE") {
ALOGI("Initialize with SUSTAINED_PERFORMANCE and VR_MODE on");
mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE");
mSustainedPerfModeOn = true;
mVRModeOn = true;
} else {
ALOGI("Initialize PowerHAL");
}
state = android::base::GetProperty(kPowerHalAudioProp, "");
if (state == "LOW_LATENCY") {
ALOGI("Initialize with AUDIO_LOW_LATENCY on");
mHintManager->DoHint("AUDIO_LOW_LATENCY");
}
}
// Methods from ::android::hardware::power::V1_0::IPower follow.
Return<void> Power::setInteractive(bool /* interactive */) {
return Void();
}
Return<void> Power::powerHint(PowerHint_1_0 hint, int32_t data) {
if (!isSupportedGovernor()) {
return Void();
}
switch(hint) {
case PowerHint_1_0::INTERACTION:
if (mVRModeOn || mSustainedPerfModeOn) {
ALOGV("%s: ignoring due to other active perf hints", __func__);
} else {
mInteractionHandler.Acquire(data);
}
break;
case PowerHint_1_0::VIDEO_ENCODE:
if (mVRModeOn || mSustainedPerfModeOn) {
ALOGV("%s: ignoring due to other active perf hints", __func__);
break;
}
ATRACE_BEGIN("video_encode");
if (mVRModeOn || mSustainedPerfModeOn) {
ALOGV("%s: ignoring due to other active perf hints", __func__);
} else {
if (data) {
// Hint until canceled
ATRACE_INT("video_encode_lock", 1);
mHintManager->DoHint("VIDEO_ENCODE");
ALOGD("VIDEO_ENCODE ON");
if (!android::base::SetProperty(kPowerHalStateProp, "VIDEO_ENCODE")) {
ALOGE("%s: could not set powerHAL state property to VIDEO_ENCODE", __func__);
}
mEncoderModeOn = true;
} else {
ATRACE_INT("video_encode_lock", 0);
mHintManager->EndHint("VIDEO_ENCODE");
ALOGD("VIDEO_ENCODE OFF");
if (!android::base::SetProperty(kPowerHalStateProp, "")) {
ALOGE("%s: could not clear powerHAL state property", __func__);
}
mEncoderModeOn = false;
}
}
ATRACE_END();
break;
case PowerHint_1_0::SUSTAINED_PERFORMANCE:
if (data && !mSustainedPerfModeOn) {
ALOGD("SUSTAINED_PERFORMANCE ON");
if (!mVRModeOn) { // Sustained mode only.
mHintManager->DoHint("SUSTAINED_PERFORMANCE");
if (!android::base::SetProperty(kPowerHalStateProp, "SUSTAINED_PERFORMANCE")) {
ALOGE("%s: could not set powerHAL state property to SUSTAINED_PERFORMANCE", __func__);
}
} else { // Sustained + VR mode.
mHintManager->EndHint("VR_MODE");
mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE");
if (!android::base::SetProperty(kPowerHalStateProp, "VR_SUSTAINED_PERFORMANCE")) {
ALOGE("%s: could not set powerHAL state property to VR_SUSTAINED_PERFORMANCE", __func__);
}
}
mSustainedPerfModeOn = true;
} else if (!data && mSustainedPerfModeOn) {
ALOGD("SUSTAINED_PERFORMANCE OFF");
mHintManager->EndHint("VR_SUSTAINED_PERFORMANCE");
mHintManager->EndHint("SUSTAINED_PERFORMANCE");
if (mVRModeOn) { // Switch back to VR Mode.
mHintManager->DoHint("VR_MODE");
if (!android::base::SetProperty(kPowerHalStateProp, "VR_MODE")) {
ALOGE("%s: could not set powerHAL state property to VR_MODE", __func__);
}
} else {
if (!android::base::SetProperty(kPowerHalStateProp, "")) {
ALOGE("%s: could not clear powerHAL state property", __func__);
}
}
mSustainedPerfModeOn = false;
}
break;
case PowerHint_1_0::VR_MODE:
if (data && !mVRModeOn) {
ALOGD("VR_MODE ON");
if (!mSustainedPerfModeOn) { // VR mode only.
mHintManager->DoHint("VR_MODE");
if (!android::base::SetProperty(kPowerHalStateProp, "VR_MODE")) {
ALOGE("%s: could not set powerHAL state property to VR_MODE", __func__);
}
} else { // Sustained + VR mode.
mHintManager->EndHint("SUSTAINED_PERFORMANCE");
mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE");
if (!android::base::SetProperty(kPowerHalStateProp, "VR_SUSTAINED_PERFORMANCE")) {
ALOGE("%s: could not set powerHAL state property to VR_SUSTAINED_PERFORMANCE", __func__);
}
}
mVRModeOn = true;
} else if (!data && mVRModeOn) {
ALOGD("VR_MODE OFF");
mHintManager->EndHint("VR_SUSTAINED_PERFORMANCE");
mHintManager->EndHint("VR_MODE");
if (mSustainedPerfModeOn) { // Switch back to sustained Mode.
mHintManager->DoHint("SUSTAINED_PERFORMANCE");
if (!android::base::SetProperty(kPowerHalStateProp, "SUSTAINED_PERFORMANCE")) {
ALOGE("%s: could not set powerHAL state property to SUSTAINED_PERFORMANCE", __func__);
}
} else {
if (!android::base::SetProperty(kPowerHalStateProp, "")) {
ALOGE("%s: could not clear powerHAL state property", __func__);
}
}
mVRModeOn = false;
}
break;
case PowerHint_1_0::LAUNCH:
ATRACE_BEGIN("launch");
if (mVRModeOn || mSustainedPerfModeOn) {
ALOGV("%s: ignoring due to other active perf hints", __func__);
} else {
if (data) {
// Hint until canceled
ATRACE_INT("launch_lock", 1);
mHintManager->DoHint("LAUNCH");
ALOGD("LAUNCH ON");
} else {
ATRACE_INT("launch_lock", 0);
mHintManager->EndHint("LAUNCH");
ALOGD("LAUNCH OFF");
}
}
ATRACE_END();
break;
default:
break;
}
return Void();
}
Return<void> Power::setFeature(Feature /*feature*/, bool /*activate*/) {
//Nothing to do
return Void();
}
Return<void> Power::getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) {
hidl_vec<PowerStatePlatformSleepState> states;
uint64_t stats[MAX_PLATFORM_STATS * MAX_RPM_PARAMS] = {0};
uint64_t *values;
struct PowerStatePlatformSleepState *state;
int ret;
states.resize(PLATFORM_SLEEP_MODES_COUNT);
ret = extract_platform_stats(stats);
if (ret != 0) {
states.resize(0);
goto done;
}
/* Update statistics for XO_shutdown */
state = &states[RPM_MODE_XO];
state->name = "XO_shutdown";
values = stats + (RPM_MODE_XO * MAX_RPM_PARAMS);
state->residencyInMsecSinceBoot = values[1];
state->totalTransitions = values[0];
state->supportedOnlyInSuspend = false;
state->voters.resize(XO_VOTERS);
for(size_t i = 0; i < XO_VOTERS; i++) {
int voter = static_cast<int>(i + XO_VOTERS_START);
state->voters[i].name = rpm_stat_map[voter].label;
values = stats + (voter * MAX_RPM_PARAMS);
state->voters[i].totalTimeInMsecVotedForSinceBoot = values[0] / RPM_CLK;
state->voters[i].totalNumberOfTimesVotedSinceBoot = values[1];
}
/* Update statistics for VMIN state */
state = &states[RPM_MODE_VMIN];
state->name = "VMIN";
values = stats + (RPM_MODE_VMIN * MAX_RPM_PARAMS);
state->residencyInMsecSinceBoot = values[1];
state->totalTransitions = values[0];
state->supportedOnlyInSuspend = false;
state->voters.resize(VMIN_VOTERS);
//Note: No filling of state voters since VMIN_VOTERS = 0
done:
_hidl_cb(states, Status::SUCCESS);
return Void();
}
static int get_wlan_low_power_stats(struct PowerStateSubsystem &subsystem) {
uint64_t stats[WLAN_POWER_PARAMS_COUNT] = {0};
struct PowerStateSubsystemSleepState *state;
int ret;
ret = extract_wlan_stats(stats);
if (ret)
return ret;
subsystem.name = "wlan";
subsystem.states.resize(WLAN_STATES_COUNT);
/* Update statistics for Active State */
state = &subsystem.states[WLAN_STATE_ACTIVE];
state->name = "Active";
state->residencyInMsecSinceBoot = stats[CUMULATIVE_TOTAL_ON_TIME_MS];
state->totalTransitions = stats[DEEP_SLEEP_ENTER_COUNTER];
state->lastEntryTimestampMs = 0; //FIXME need a new value from Qcom
state->supportedOnlyInSuspend = false;
/* Update statistics for Deep-Sleep state */
state = &subsystem.states[WLAN_STATE_DEEP_SLEEP];
state->name = "Deep-Sleep";
state->residencyInMsecSinceBoot = stats[CUMULATIVE_SLEEP_TIME_MS];
state->totalTransitions = stats[DEEP_SLEEP_ENTER_COUNTER];
state->lastEntryTimestampMs = stats[LAST_DEEP_SLEEP_ENTER_TSTAMP_MS];
state->supportedOnlyInSuspend = false;
return 0;
}
// Methods from ::android::hardware::power::V1_1::IPower follow.
Return<void> Power::getSubsystemLowPowerStats(getSubsystemLowPowerStats_cb _hidl_cb) {
hidl_vec<PowerStateSubsystem> subsystems;
int ret;
subsystems.resize(SUBSYSTEM_COUNT);
//We currently have only one Subsystem for WLAN
ret = get_wlan_low_power_stats(subsystems[SUBSYSTEM_WLAN]);
if (ret != 0)
goto done;
//Add query for other subsystems here
done:
_hidl_cb(subsystems, Status::SUCCESS);
return Void();
}
bool Power::isSupportedGovernor() {
std::string buf;
if (android::base::ReadFileToString("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor", &buf)) {
buf = android::base::Trim(buf);
}
// Only support EAS 1.2, legacy EAS
if (buf == "schedutil" || buf == "sched") {
return true;
} else {
LOG(ERROR) << "Governor not supported by powerHAL, skipping";
return false;
}
}
Return<void> Power::powerHintAsync(PowerHint_1_0 hint, int32_t data) {
// just call the normal power hint in this oneway function
return powerHint(hint, data);
}
// Methods from ::android::hardware::power::V1_2::IPower follow.
Return<void> Power::powerHintAsync_1_2(PowerHint_1_2 hint, int32_t data) {
if (!isSupportedGovernor()) {
return Void();
}
switch(hint) {
case PowerHint_1_2::AUDIO_LOW_LATENCY:
ATRACE_BEGIN("audio_low_latency");
if (data) {
// Hint until canceled
ATRACE_INT("audio_low_latency_lock", 1);
mHintManager->DoHint("AUDIO_LOW_LATENCY");
ALOGD("AUDIO LOW LATENCY ON");
if (!android::base::SetProperty(kPowerHalAudioProp, "LOW_LATENCY")) {
ALOGE("%s: could not set powerHAL audio state property to LOW_LATENCY", __func__);
}
} else {
ATRACE_INT("audio_low_latency_lock", 0);
mHintManager->EndHint("AUDIO_LOW_LATENCY");
ALOGD("AUDIO LOW LATENCY OFF");
if (!android::base::SetProperty(kPowerHalAudioProp, "")) {
ALOGE("%s: could not clear powerHAL audio state property", __func__);
}
}
ATRACE_END();
break;
case PowerHint_1_2::AUDIO_STREAMING:
ATRACE_BEGIN("audio_streaming");
if (data) {
// Hint until canceled
ATRACE_INT("audio_streaming_lock", 1);
mHintManager->DoHint("AUDIO_STREAMING");
ALOGD("AUDIO STREAMING ON");
} else {
ATRACE_INT("audio_streaming_lock", 0);
mHintManager->EndHint("AUDIO_STREAMING");
ALOGD("AUDIO STREAMING OFF");
}
ATRACE_END();
break;
case PowerHint_1_2::CAMERA_LAUNCH:
ATRACE_BEGIN("camera_launch");
if (data > 0) {
ATRACE_INT("camera_launch_lock", 1);
mHintManager->DoHint("CAMERA_LAUNCH", std::chrono::milliseconds(data));
ALOGD("CAMERA LAUNCH ON: %d MS, LAUNCH ON: 2500 MS", data);
// boosts 2.5s for launching
mHintManager->DoHint("LAUNCH", std::chrono::milliseconds(2500));
} else if (data == 0) {
ATRACE_INT("camera_launch_lock", 0);
mHintManager->EndHint("CAMERA_LAUNCH");
ALOGD("CAMERA LAUNCH OFF");
} else {
ALOGE("CAMERA LAUNCH INVALID DATA: %d", data);
}
ATRACE_END();
break;
case PowerHint_1_2::CAMERA_STREAMING:
ATRACE_BEGIN("camera_streaming");
if (data > 0) {
ATRACE_INT("camera_streaming_lock", 1);
mHintManager->DoHint("CAMERA_STREAMING", std::chrono::milliseconds(data));
ALOGD("CAMERA STREAMING ON: %d MS", data);
} else if (data == 0) {
ATRACE_INT("camera_streaming_lock", 0);
mHintManager->EndHint("CAMERA_STREAMING");
ALOGD("CAMERA STREAMING OFF");
} else {
ALOGE("CAMERA STREAMING INVALID DATA: %d", data);
}
ATRACE_END();
break;
case PowerHint_1_2::CAMERA_SHOT:
ATRACE_BEGIN("camera_shot");
if (data > 0) {
ATRACE_INT("camera_shot_lock", 1);
mHintManager->DoHint("CAMERA_SHOT", std::chrono::milliseconds(data));
ALOGD("CAMERA SHOT ON: %d MS", data);
} else if (data == 0) {
ATRACE_INT("camera_shot_lock", 0);
mHintManager->EndHint("CAMERA_SHOT");
ALOGD("CAMERA SHOT OFF");
} else {
ALOGE("CAMERA SHOT INVALID DATA: %d", data);
}
ATRACE_END();
break;
default:
return powerHint(static_cast<PowerHint_1_0>(hint), data);
}
return Void();
}
} // namespace implementation
} // namespace V1_2
} // namespace power
} // namespace hardware
} // namespace android