Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
877c1a0564 | ||
|
|
201fd3cc32 | ||
|
|
56626e0201 | ||
|
|
edb30cd0c5 | ||
|
|
a65af94562 | ||
|
|
dd3baf47d3 | ||
|
|
4d5a25b7c1 | ||
|
|
bf39dfb28b |
@@ -1,6 +1,7 @@
|
||||
<manifest version="1.0" type="device">
|
||||
<hal format="aidl">
|
||||
<name>android.hardware.camera.provider</name>
|
||||
<version>1</version>
|
||||
<fqname>ICameraProvider/internal/0</fqname>
|
||||
</hal>
|
||||
</manifest>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<manifest version="1.0" type="device">
|
||||
<hal format="aidl">
|
||||
<name>android.hardware.biometrics.fingerprint</name>
|
||||
<version>4</version>
|
||||
<fqname>IFingerprint/default</fqname>
|
||||
</hal>
|
||||
</manifest>
|
||||
|
||||
@@ -17,7 +17,7 @@ cc_binary {
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"libbinder_ndk",
|
||||
"android.hardware.light-V1-ndk",
|
||||
"android.hardware.light-V2-ndk",
|
||||
],
|
||||
vendor: true,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<manifest version="1.0" type="device">
|
||||
<hal format="aidl">
|
||||
<name>android.hardware.light</name>
|
||||
<version>2</version>
|
||||
<fqname>ILights/default</fqname>
|
||||
</hal>
|
||||
</manifest>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<manifest version="1.0" type="device">
|
||||
<hal format="aidl">
|
||||
<name>android.hardware.memtrack</name>
|
||||
<version>1</version>
|
||||
<fqname>IMemtrack/default</fqname>
|
||||
</hal>
|
||||
</manifest>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//
|
||||
// Copyright (C) 2020 The Android Open Source Project
|
||||
// Copyright (C) 2022-2024 The LineageOS Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -15,27 +16,23 @@
|
||||
|
||||
cc_binary {
|
||||
name: "android.hardware.sensors-service.samsung-multihal",
|
||||
defaults: [
|
||||
"hidl_defaults",
|
||||
],
|
||||
vendor: true,
|
||||
relative_install_path: "hw",
|
||||
srcs: [
|
||||
"ConvertUtils.cpp",
|
||||
"HalProxyAidl.cpp",
|
||||
"HalProxySamsung.cpp",
|
||||
"service.cpp",
|
||||
],
|
||||
local_include_dirs: ["include"],
|
||||
init_rc: ["android.hardware.sensors-service.samsung-multihal.rc"],
|
||||
vintf_fragments: ["android.hardware.sensors-samsung-multihal.xml"],
|
||||
header_libs: [
|
||||
"android.hardware.sensors@2.X-multihal.header",
|
||||
"android.hardware.sensors@2.X-shared-utils",
|
||||
],
|
||||
shared_libs: [
|
||||
"android.hardware.sensors@2.0",
|
||||
"android.hardware.sensors@2.0-ScopedWakelock",
|
||||
"android.hardware.sensors@2.1",
|
||||
"android.hardware.sensors-V1-ndk",
|
||||
"android.hardware.sensors-V2-ndk",
|
||||
"libbase",
|
||||
"libbinder_ndk",
|
||||
"libcutils",
|
||||
@@ -48,6 +45,7 @@ cc_binary {
|
||||
static_libs: [
|
||||
"android.hardware.sensors@1.0-convert",
|
||||
"android.hardware.sensors@2.X-multihal",
|
||||
"android.hardware.sensors@aidl-multihal",
|
||||
"libaidlcommonsupport",
|
||||
],
|
||||
}
|
||||
|
||||
@@ -1,363 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "ConvertUtils.h"
|
||||
#include <android-base/logging.h>
|
||||
#include <log/log.h>
|
||||
|
||||
using AidlSensorInfo = ::aidl::android::hardware::sensors::SensorInfo;
|
||||
using AidlSensorType = ::aidl::android::hardware::sensors::SensorType;
|
||||
using AidlEvent = ::aidl::android::hardware::sensors::Event;
|
||||
using AidlSensorStatus = ::aidl::android::hardware::sensors::SensorStatus;
|
||||
using ::aidl::android::hardware::sensors::AdditionalInfo;
|
||||
using ::aidl::android::hardware::sensors::DynamicSensorInfo;
|
||||
using ::android::hardware::sensors::V1_0::MetaDataEventType;
|
||||
using V1_0SensorStatus = ::android::hardware::sensors::V1_0::SensorStatus;
|
||||
using ::android::hardware::sensors::V1_0::AdditionalInfoType;
|
||||
using V2_1SensorInfo = ::android::hardware::sensors::V2_1::SensorInfo;
|
||||
using V2_1Event = ::android::hardware::sensors::V2_1::Event;
|
||||
using V2_1SensorType = ::android::hardware::sensors::V2_1::SensorType;
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace sensors {
|
||||
namespace implementation {
|
||||
|
||||
AidlSensorInfo convertSensorInfo(const V2_1SensorInfo& sensorInfo) {
|
||||
AidlSensorInfo aidlSensorInfo;
|
||||
aidlSensorInfo.sensorHandle = sensorInfo.sensorHandle;
|
||||
aidlSensorInfo.name = sensorInfo.name;
|
||||
aidlSensorInfo.vendor = sensorInfo.vendor;
|
||||
aidlSensorInfo.version = sensorInfo.version;
|
||||
aidlSensorInfo.type = (AidlSensorType)sensorInfo.type;
|
||||
aidlSensorInfo.typeAsString = sensorInfo.typeAsString;
|
||||
aidlSensorInfo.maxRange = sensorInfo.maxRange;
|
||||
aidlSensorInfo.resolution = sensorInfo.resolution;
|
||||
aidlSensorInfo.power = sensorInfo.power;
|
||||
aidlSensorInfo.minDelayUs = sensorInfo.minDelay;
|
||||
aidlSensorInfo.fifoReservedEventCount = sensorInfo.fifoReservedEventCount;
|
||||
aidlSensorInfo.fifoMaxEventCount = sensorInfo.fifoMaxEventCount;
|
||||
aidlSensorInfo.requiredPermission = sensorInfo.requiredPermission;
|
||||
aidlSensorInfo.maxDelayUs = sensorInfo.maxDelay;
|
||||
aidlSensorInfo.flags = sensorInfo.flags;
|
||||
return aidlSensorInfo;
|
||||
}
|
||||
|
||||
void convertToHidlEvent(const AidlEvent& aidlEvent, V2_1Event* hidlEvent) {
|
||||
static_assert(decltype(hidlEvent->u.data)::elementCount() == 16);
|
||||
hidlEvent->timestamp = aidlEvent.timestamp;
|
||||
hidlEvent->sensorHandle = aidlEvent.sensorHandle;
|
||||
hidlEvent->sensorType = (V2_1SensorType)aidlEvent.sensorType;
|
||||
|
||||
switch (aidlEvent.sensorType) {
|
||||
case AidlSensorType::META_DATA:
|
||||
hidlEvent->u.meta.what =
|
||||
(MetaDataEventType)aidlEvent.payload.get<Event::EventPayload::meta>().what;
|
||||
break;
|
||||
case AidlSensorType::ACCELEROMETER:
|
||||
case AidlSensorType::MAGNETIC_FIELD:
|
||||
case AidlSensorType::ORIENTATION:
|
||||
case AidlSensorType::GYROSCOPE:
|
||||
case AidlSensorType::GRAVITY:
|
||||
case AidlSensorType::LINEAR_ACCELERATION:
|
||||
hidlEvent->u.vec3.x = aidlEvent.payload.get<Event::EventPayload::vec3>().x;
|
||||
hidlEvent->u.vec3.y = aidlEvent.payload.get<Event::EventPayload::vec3>().y;
|
||||
hidlEvent->u.vec3.z = aidlEvent.payload.get<Event::EventPayload::vec3>().z;
|
||||
hidlEvent->u.vec3.status =
|
||||
(V1_0SensorStatus)aidlEvent.payload.get<Event::EventPayload::vec3>().status;
|
||||
break;
|
||||
case AidlSensorType::GAME_ROTATION_VECTOR:
|
||||
hidlEvent->u.vec4.x = aidlEvent.payload.get<Event::EventPayload::vec4>().x;
|
||||
hidlEvent->u.vec4.y = aidlEvent.payload.get<Event::EventPayload::vec4>().y;
|
||||
hidlEvent->u.vec4.z = aidlEvent.payload.get<Event::EventPayload::vec4>().z;
|
||||
hidlEvent->u.vec4.w = aidlEvent.payload.get<Event::EventPayload::vec4>().w;
|
||||
break;
|
||||
case AidlSensorType::ROTATION_VECTOR:
|
||||
case AidlSensorType::GEOMAGNETIC_ROTATION_VECTOR:
|
||||
std::copy(aidlEvent.payload.get<Event::EventPayload::data>().values.data(),
|
||||
aidlEvent.payload.get<Event::EventPayload::data>().values.data() + 5,
|
||||
hidlEvent->u.data.data());
|
||||
break;
|
||||
case AidlSensorType::ACCELEROMETER_UNCALIBRATED:
|
||||
case AidlSensorType::MAGNETIC_FIELD_UNCALIBRATED:
|
||||
case AidlSensorType::GYROSCOPE_UNCALIBRATED:
|
||||
hidlEvent->u.uncal.x = aidlEvent.payload.get<Event::EventPayload::uncal>().x;
|
||||
hidlEvent->u.uncal.y = aidlEvent.payload.get<Event::EventPayload::uncal>().y;
|
||||
hidlEvent->u.uncal.z = aidlEvent.payload.get<Event::EventPayload::uncal>().z;
|
||||
hidlEvent->u.uncal.x_bias = aidlEvent.payload.get<Event::EventPayload::uncal>().xBias;
|
||||
hidlEvent->u.uncal.y_bias = aidlEvent.payload.get<Event::EventPayload::uncal>().yBias;
|
||||
hidlEvent->u.uncal.z_bias = aidlEvent.payload.get<Event::EventPayload::uncal>().zBias;
|
||||
break;
|
||||
case AidlSensorType::DEVICE_ORIENTATION:
|
||||
case AidlSensorType::LIGHT:
|
||||
case AidlSensorType::PRESSURE:
|
||||
case AidlSensorType::PROXIMITY:
|
||||
case AidlSensorType::RELATIVE_HUMIDITY:
|
||||
case AidlSensorType::AMBIENT_TEMPERATURE:
|
||||
case AidlSensorType::SIGNIFICANT_MOTION:
|
||||
case AidlSensorType::STEP_DETECTOR:
|
||||
case AidlSensorType::TILT_DETECTOR:
|
||||
case AidlSensorType::WAKE_GESTURE:
|
||||
case AidlSensorType::GLANCE_GESTURE:
|
||||
case AidlSensorType::PICK_UP_GESTURE:
|
||||
case AidlSensorType::WRIST_TILT_GESTURE:
|
||||
case AidlSensorType::STATIONARY_DETECT:
|
||||
case AidlSensorType::MOTION_DETECT:
|
||||
case AidlSensorType::HEART_BEAT:
|
||||
case AidlSensorType::LOW_LATENCY_OFFBODY_DETECT:
|
||||
case AidlSensorType::HINGE_ANGLE:
|
||||
hidlEvent->u.scalar = aidlEvent.payload.get<Event::EventPayload::scalar>();
|
||||
break;
|
||||
case AidlSensorType::STEP_COUNTER:
|
||||
hidlEvent->u.stepCount = aidlEvent.payload.get<AidlEvent::EventPayload::stepCount>();
|
||||
break;
|
||||
case AidlSensorType::HEART_RATE:
|
||||
hidlEvent->u.heartRate.bpm =
|
||||
aidlEvent.payload.get<AidlEvent::EventPayload::heartRate>().bpm;
|
||||
hidlEvent->u.heartRate.status =
|
||||
(V1_0SensorStatus)aidlEvent.payload.get<Event::EventPayload::heartRate>()
|
||||
.status;
|
||||
break;
|
||||
case AidlSensorType::POSE_6DOF:
|
||||
std::copy(std::begin(aidlEvent.payload.get<AidlEvent::EventPayload::pose6DOF>().values),
|
||||
std::end(aidlEvent.payload.get<AidlEvent::EventPayload::pose6DOF>().values),
|
||||
hidlEvent->u.pose6DOF.data());
|
||||
break;
|
||||
case AidlSensorType::DYNAMIC_SENSOR_META:
|
||||
hidlEvent->u.dynamic.connected =
|
||||
aidlEvent.payload.get<Event::EventPayload::dynamic>().connected;
|
||||
hidlEvent->u.dynamic.sensorHandle =
|
||||
aidlEvent.payload.get<Event::EventPayload::dynamic>().sensorHandle;
|
||||
std::copy(
|
||||
std::begin(
|
||||
aidlEvent.payload.get<AidlEvent::EventPayload::dynamic>().uuid.values),
|
||||
std::end(aidlEvent.payload.get<AidlEvent::EventPayload::dynamic>().uuid.values),
|
||||
hidlEvent->u.dynamic.uuid.data());
|
||||
break;
|
||||
case AidlSensorType::ADDITIONAL_INFO: {
|
||||
const AdditionalInfo& additionalInfo =
|
||||
aidlEvent.payload.get<AidlEvent::EventPayload::additional>();
|
||||
hidlEvent->u.additional.type = (AdditionalInfoType)additionalInfo.type;
|
||||
hidlEvent->u.additional.serial = additionalInfo.serial;
|
||||
|
||||
switch (additionalInfo.payload.getTag()) {
|
||||
case AdditionalInfo::AdditionalInfoPayload::Tag::dataInt32: {
|
||||
const auto& aidlData =
|
||||
additionalInfo.payload
|
||||
.get<AdditionalInfo::AdditionalInfoPayload::dataInt32>()
|
||||
.values;
|
||||
std::copy(std::begin(aidlData), std::end(aidlData),
|
||||
hidlEvent->u.additional.u.data_int32.data());
|
||||
break;
|
||||
}
|
||||
case AdditionalInfo::AdditionalInfoPayload::Tag::dataFloat: {
|
||||
const auto& aidlData =
|
||||
additionalInfo.payload
|
||||
.get<AdditionalInfo::AdditionalInfoPayload::dataFloat>()
|
||||
.values;
|
||||
std::copy(std::begin(aidlData), std::end(aidlData),
|
||||
hidlEvent->u.additional.u.data_float.data());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ALOGE("Invalid sensor additioanl info tag: %d",
|
||||
static_cast<int32_t>(additionalInfo.payload.getTag()));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AidlSensorType::HEAD_TRACKER: {
|
||||
const auto& ht = aidlEvent.payload.get<Event::EventPayload::headTracker>();
|
||||
hidlEvent->u.data[0] = ht.rx;
|
||||
hidlEvent->u.data[1] = ht.ry;
|
||||
hidlEvent->u.data[2] = ht.rz;
|
||||
hidlEvent->u.data[3] = ht.vx;
|
||||
hidlEvent->u.data[4] = ht.vy;
|
||||
hidlEvent->u.data[5] = ht.vz;
|
||||
|
||||
// IMPORTANT: Because we want to preserve the data range of discontinuityCount,
|
||||
// we assume the data can be interpreted as an int32_t directly (e.g. the underlying
|
||||
// HIDL HAL must be using memcpy or equivalent to store this value).
|
||||
*(reinterpret_cast<int32_t*>(&hidlEvent->u.data[6])) = ht.discontinuityCount;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
CHECK_GE((int32_t)aidlEvent.sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
|
||||
std::copy(std::begin(aidlEvent.payload.get<AidlEvent::EventPayload::data>().values),
|
||||
std::end(aidlEvent.payload.get<AidlEvent::EventPayload::data>().values),
|
||||
hidlEvent->u.data.data());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void convertToAidlEvent(const V2_1Event& hidlEvent, AidlEvent* aidlEvent) {
|
||||
static_assert(decltype(hidlEvent.u.data)::elementCount() == 16);
|
||||
aidlEvent->timestamp = hidlEvent.timestamp;
|
||||
aidlEvent->sensorHandle = hidlEvent.sensorHandle;
|
||||
aidlEvent->sensorType = (AidlSensorType)hidlEvent.sensorType;
|
||||
switch (hidlEvent.sensorType) {
|
||||
case V2_1SensorType::META_DATA: {
|
||||
AidlEvent::EventPayload::MetaData meta;
|
||||
meta.what = (Event::EventPayload::MetaData::MetaDataEventType)hidlEvent.u.meta.what;
|
||||
aidlEvent->payload.set<Event::EventPayload::meta>(meta);
|
||||
break;
|
||||
}
|
||||
case V2_1SensorType::ACCELEROMETER:
|
||||
case V2_1SensorType::MAGNETIC_FIELD:
|
||||
case V2_1SensorType::ORIENTATION:
|
||||
case V2_1SensorType::GYROSCOPE:
|
||||
case V2_1SensorType::GRAVITY:
|
||||
case V2_1SensorType::LINEAR_ACCELERATION: {
|
||||
AidlEvent::EventPayload::Vec3 vec3;
|
||||
vec3.x = hidlEvent.u.vec3.x;
|
||||
vec3.y = hidlEvent.u.vec3.y;
|
||||
vec3.z = hidlEvent.u.vec3.z;
|
||||
vec3.status = (SensorStatus)hidlEvent.u.vec3.status;
|
||||
aidlEvent->payload.set<Event::EventPayload::vec3>(vec3);
|
||||
break;
|
||||
}
|
||||
case V2_1SensorType::GAME_ROTATION_VECTOR: {
|
||||
AidlEvent::EventPayload::Vec4 vec4;
|
||||
vec4.x = hidlEvent.u.vec4.x;
|
||||
vec4.y = hidlEvent.u.vec4.y;
|
||||
vec4.z = hidlEvent.u.vec4.z;
|
||||
vec4.w = hidlEvent.u.vec4.w;
|
||||
aidlEvent->payload.set<Event::EventPayload::vec4>(vec4);
|
||||
break;
|
||||
}
|
||||
case V2_1SensorType::ROTATION_VECTOR:
|
||||
case V2_1SensorType::GEOMAGNETIC_ROTATION_VECTOR: {
|
||||
AidlEvent::EventPayload::Data data;
|
||||
std::copy(hidlEvent.u.data.data(), hidlEvent.u.data.data() + 5,
|
||||
std::begin(data.values));
|
||||
aidlEvent->payload.set<Event::EventPayload::data>(data);
|
||||
break;
|
||||
}
|
||||
case V2_1SensorType::MAGNETIC_FIELD_UNCALIBRATED:
|
||||
case V2_1SensorType::GYROSCOPE_UNCALIBRATED:
|
||||
case V2_1SensorType::ACCELEROMETER_UNCALIBRATED: {
|
||||
AidlEvent::EventPayload::Uncal uncal;
|
||||
uncal.x = hidlEvent.u.uncal.x;
|
||||
uncal.y = hidlEvent.u.uncal.y;
|
||||
uncal.z = hidlEvent.u.uncal.z;
|
||||
uncal.xBias = hidlEvent.u.uncal.x_bias;
|
||||
uncal.yBias = hidlEvent.u.uncal.y_bias;
|
||||
uncal.zBias = hidlEvent.u.uncal.z_bias;
|
||||
aidlEvent->payload.set<Event::EventPayload::uncal>(uncal);
|
||||
break;
|
||||
}
|
||||
case V2_1SensorType::DEVICE_ORIENTATION:
|
||||
case V2_1SensorType::LIGHT:
|
||||
case V2_1SensorType::PRESSURE:
|
||||
case V2_1SensorType::PROXIMITY:
|
||||
case V2_1SensorType::RELATIVE_HUMIDITY:
|
||||
case V2_1SensorType::AMBIENT_TEMPERATURE:
|
||||
case V2_1SensorType::SIGNIFICANT_MOTION:
|
||||
case V2_1SensorType::STEP_DETECTOR:
|
||||
case V2_1SensorType::TILT_DETECTOR:
|
||||
case V2_1SensorType::WAKE_GESTURE:
|
||||
case V2_1SensorType::GLANCE_GESTURE:
|
||||
case V2_1SensorType::PICK_UP_GESTURE:
|
||||
case V2_1SensorType::WRIST_TILT_GESTURE:
|
||||
case V2_1SensorType::STATIONARY_DETECT:
|
||||
case V2_1SensorType::MOTION_DETECT:
|
||||
case V2_1SensorType::HEART_BEAT:
|
||||
case V2_1SensorType::LOW_LATENCY_OFFBODY_DETECT:
|
||||
case V2_1SensorType::HINGE_ANGLE:
|
||||
aidlEvent->payload.set<Event::EventPayload::scalar>(hidlEvent.u.scalar);
|
||||
break;
|
||||
case V2_1SensorType::STEP_COUNTER:
|
||||
aidlEvent->payload.set<Event::EventPayload::stepCount>(hidlEvent.u.stepCount);
|
||||
break;
|
||||
case V2_1SensorType::HEART_RATE: {
|
||||
AidlEvent::EventPayload::HeartRate heartRate;
|
||||
heartRate.bpm = hidlEvent.u.heartRate.bpm;
|
||||
heartRate.status = (SensorStatus)hidlEvent.u.heartRate.status;
|
||||
aidlEvent->payload.set<Event::EventPayload::heartRate>(heartRate);
|
||||
break;
|
||||
}
|
||||
case V2_1SensorType::POSE_6DOF: {
|
||||
AidlEvent::EventPayload::Pose6Dof pose6Dof;
|
||||
std::copy(hidlEvent.u.pose6DOF.data(),
|
||||
hidlEvent.u.pose6DOF.data() + hidlEvent.u.pose6DOF.size(),
|
||||
std::begin(pose6Dof.values));
|
||||
aidlEvent->payload.set<Event::EventPayload::pose6DOF>(pose6Dof);
|
||||
break;
|
||||
}
|
||||
case V2_1SensorType::DYNAMIC_SENSOR_META: {
|
||||
DynamicSensorInfo dynamicSensorInfo;
|
||||
dynamicSensorInfo.connected = hidlEvent.u.dynamic.connected;
|
||||
dynamicSensorInfo.sensorHandle = hidlEvent.u.dynamic.sensorHandle;
|
||||
std::copy(hidlEvent.u.dynamic.uuid.data(),
|
||||
hidlEvent.u.dynamic.uuid.data() + hidlEvent.u.dynamic.uuid.size(),
|
||||
std::begin(dynamicSensorInfo.uuid.values));
|
||||
aidlEvent->payload.set<Event::EventPayload::dynamic>(dynamicSensorInfo);
|
||||
break;
|
||||
}
|
||||
case V2_1SensorType::ADDITIONAL_INFO: {
|
||||
AdditionalInfo additionalInfo;
|
||||
additionalInfo.type = (AdditionalInfo::AdditionalInfoType)hidlEvent.u.additional.type;
|
||||
additionalInfo.serial = hidlEvent.u.additional.serial;
|
||||
|
||||
AdditionalInfo::AdditionalInfoPayload::Int32Values int32Values;
|
||||
std::copy(hidlEvent.u.additional.u.data_int32.data(),
|
||||
hidlEvent.u.additional.u.data_int32.data() +
|
||||
hidlEvent.u.additional.u.data_int32.size(),
|
||||
std::begin(int32Values.values));
|
||||
additionalInfo.payload.set<AdditionalInfo::AdditionalInfoPayload::dataInt32>(
|
||||
int32Values);
|
||||
aidlEvent->payload.set<Event::EventPayload::additional>(additionalInfo);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (static_cast<int32_t>(hidlEvent.sensorType) ==
|
||||
static_cast<int32_t>(AidlSensorType::HEAD_TRACKER)) {
|
||||
Event::EventPayload::HeadTracker headTracker;
|
||||
headTracker.rx = hidlEvent.u.data[0];
|
||||
headTracker.ry = hidlEvent.u.data[1];
|
||||
headTracker.rz = hidlEvent.u.data[2];
|
||||
headTracker.vx = hidlEvent.u.data[3];
|
||||
headTracker.vy = hidlEvent.u.data[4];
|
||||
headTracker.vz = hidlEvent.u.data[5];
|
||||
|
||||
// IMPORTANT: Because we want to preserve the data range of discontinuityCount,
|
||||
// we assume the data can be interpreted as an int32_t directly (e.g. the underlying
|
||||
// HIDL HAL must be using memcpy or equivalent to store this value).
|
||||
headTracker.discontinuityCount =
|
||||
*(reinterpret_cast<const int32_t*>(&hidlEvent.u.data[6]));
|
||||
|
||||
aidlEvent->payload.set<Event::EventPayload::Tag::headTracker>(headTracker);
|
||||
} else {
|
||||
CHECK_GE((int32_t)hidlEvent.sensorType,
|
||||
(int32_t)V2_1SensorType::DEVICE_PRIVATE_BASE);
|
||||
AidlEvent::EventPayload::Data data;
|
||||
std::copy(hidlEvent.u.data.data(),
|
||||
hidlEvent.u.data.data() + hidlEvent.u.data.size(),
|
||||
std::begin(data.values));
|
||||
aidlEvent->payload.set<Event::EventPayload::data>(data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace sensors
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -1,269 +0,0 @@
|
||||
/*
|
||||
* 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 VERBOSE
|
||||
|
||||
#include "HalProxyAidl.h"
|
||||
#include <aidlcommonsupport/NativeHandle.h>
|
||||
#include <fmq/AidlMessageQueue.h>
|
||||
#include <hidl/Status.h>
|
||||
#include "ConvertUtils.h"
|
||||
#include "EventMessageQueueWrapperAidl.h"
|
||||
#include "ISensorsCallbackWrapperAidl.h"
|
||||
#include "WakeLockMessageQueueWrapperAidl.h"
|
||||
#include "convertV2_1.h"
|
||||
|
||||
using ::aidl::android::hardware::common::fmq::MQDescriptor;
|
||||
using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
|
||||
using ::aidl::android::hardware::sensors::ISensors;
|
||||
using ::aidl::android::hardware::sensors::ISensorsCallback;
|
||||
using ::aidl::android::hardware::sensors::SensorInfo;
|
||||
using ::android::hardware::sensors::V2_1::implementation::convertToOldEvent;
|
||||
using ::ndk::ScopedAStatus;
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace sensors {
|
||||
namespace implementation {
|
||||
|
||||
static ScopedAStatus
|
||||
resultToAStatus(::android::hardware::sensors::V1_0::Result result) {
|
||||
switch (result) {
|
||||
case ::android::hardware::sensors::V1_0::Result::OK:
|
||||
return ScopedAStatus::ok();
|
||||
case ::android::hardware::sensors::V1_0::Result::PERMISSION_DENIED:
|
||||
return ScopedAStatus::fromExceptionCode(EX_SECURITY);
|
||||
case ::android::hardware::sensors::V1_0::Result::NO_MEMORY:
|
||||
return ScopedAStatus::fromServiceSpecificError(ISensors::ERROR_NO_MEMORY);
|
||||
case ::android::hardware::sensors::V1_0::Result::BAD_VALUE:
|
||||
return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
case ::android::hardware::sensors::V1_0::Result::INVALID_OPERATION:
|
||||
return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
default:
|
||||
return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
static ::android::hardware::sensors::V1_0::RateLevel convertRateLevel(
|
||||
ISensors::RateLevel rateLevel) {
|
||||
switch (rateLevel) {
|
||||
case ISensors::RateLevel::STOP:
|
||||
return ::android::hardware::sensors::V1_0::RateLevel::STOP;
|
||||
case ISensors::RateLevel::NORMAL:
|
||||
return ::android::hardware::sensors::V1_0::RateLevel::NORMAL;
|
||||
case ISensors::RateLevel::FAST:
|
||||
return ::android::hardware::sensors::V1_0::RateLevel::FAST;
|
||||
case ISensors::RateLevel::VERY_FAST:
|
||||
return ::android::hardware::sensors::V1_0::RateLevel::VERY_FAST;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
static ::android::hardware::sensors::V1_0::OperationMode convertOperationMode(
|
||||
ISensors::OperationMode operationMode) {
|
||||
switch (operationMode) {
|
||||
case ISensors::OperationMode::NORMAL:
|
||||
return ::android::hardware::sensors::V1_0::OperationMode::NORMAL;
|
||||
case ISensors::OperationMode::DATA_INJECTION:
|
||||
return ::android::hardware::sensors::V1_0::OperationMode::DATA_INJECTION;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
static ::android::hardware::sensors::V1_0::SharedMemType convertSharedMemType(
|
||||
ISensors::SharedMemInfo::SharedMemType sharedMemType) {
|
||||
switch (sharedMemType) {
|
||||
case ISensors::SharedMemInfo::SharedMemType::ASHMEM:
|
||||
return ::android::hardware::sensors::V1_0::SharedMemType::ASHMEM;
|
||||
case ISensors::SharedMemInfo::SharedMemType::GRALLOC:
|
||||
return ::android::hardware::sensors::V1_0::SharedMemType::GRALLOC;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
static ::android::hardware::sensors::V1_0::SharedMemFormat convertSharedMemFormat(
|
||||
ISensors::SharedMemInfo::SharedMemFormat sharedMemFormat) {
|
||||
switch (sharedMemFormat) {
|
||||
case ISensors::SharedMemInfo::SharedMemFormat::SENSORS_EVENT:
|
||||
return ::android::hardware::sensors::V1_0::SharedMemFormat::SENSORS_EVENT;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
static ::android::hardware::sensors::V1_0::SharedMemInfo convertSharedMemInfo(
|
||||
const ISensors::SharedMemInfo& sharedMemInfo) {
|
||||
::android::hardware::sensors::V1_0::SharedMemInfo v1SharedMemInfo;
|
||||
v1SharedMemInfo.type = convertSharedMemType(sharedMemInfo.type);
|
||||
v1SharedMemInfo.format = convertSharedMemFormat(sharedMemInfo.format);
|
||||
v1SharedMemInfo.size = sharedMemInfo.size;
|
||||
v1SharedMemInfo.memoryHandle =
|
||||
::android::hardware::hidl_handle(::android::makeFromAidl(sharedMemInfo.memoryHandle));
|
||||
return v1SharedMemInfo;
|
||||
}
|
||||
|
||||
ScopedAStatus HalProxyAidl::activate(int32_t in_sensorHandle, bool in_enabled) {
|
||||
return resultToAStatus(HalProxy::activate(in_sensorHandle, in_enabled));
|
||||
}
|
||||
|
||||
ScopedAStatus HalProxyAidl::batch(int32_t in_sensorHandle,
|
||||
int64_t in_samplingPeriodNs,
|
||||
int64_t in_maxReportLatencyNs) {
|
||||
return resultToAStatus(HalProxy::batch(in_sensorHandle, in_samplingPeriodNs,
|
||||
in_maxReportLatencyNs));
|
||||
}
|
||||
|
||||
ScopedAStatus HalProxyAidl::configDirectReport(int32_t in_sensorHandle,
|
||||
int32_t in_channelHandle,
|
||||
ISensors::RateLevel in_rate,
|
||||
int32_t *_aidl_return) {
|
||||
ScopedAStatus status =
|
||||
ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
HalProxy::configDirectReport(
|
||||
in_sensorHandle, in_channelHandle, convertRateLevel(in_rate),
|
||||
[&status, _aidl_return](::android::hardware::sensors::V1_0::Result result,
|
||||
int32_t reportToken) {
|
||||
status = resultToAStatus(result);
|
||||
*_aidl_return = reportToken;
|
||||
});
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
ScopedAStatus HalProxyAidl::flush(int32_t in_sensorHandle) {
|
||||
return resultToAStatus(HalProxy::flush(in_sensorHandle));
|
||||
}
|
||||
|
||||
|
||||
ScopedAStatus HalProxyAidl::getSensorsList(
|
||||
std::vector<::aidl::android::hardware::sensors::SensorInfo> *_aidl_return) {
|
||||
for (const auto &sensor : HalProxy::getSensors()) {
|
||||
SensorInfo dst = sensor.second;
|
||||
|
||||
if (dst.requiredPermission == "com.samsung.permission.SSENSOR") {
|
||||
dst.requiredPermission = "";
|
||||
}
|
||||
|
||||
if (dst.typeAsString == "com.samsung.sensor.physical_proximity" ||
|
||||
dst.typeAsString == "com.samsung.sensor.hover_proximity") {
|
||||
ALOGI("Fixing %s", dst.typeAsString.c_str());
|
||||
dst.type = ::android::hardware::sensors::V2_1::SensorType::PROXIMITY;
|
||||
dst.typeAsString = SENSOR_STRING_TYPE_PROXIMITY;
|
||||
dst.maxRange = 1;
|
||||
}
|
||||
|
||||
#ifdef VERBOSE
|
||||
ALOGI( "SENSOR NAME:%s ", dst.name.c_str());
|
||||
ALOGI( " VENDOR:%s ", dst.name.c_str());
|
||||
ALOGI( " TYPE:%d ", (uint32_t)dst.type);
|
||||
ALOGI( " TYPE_AS_STRING:%s ", dst.typeAsString.c_str());
|
||||
#endif
|
||||
|
||||
_aidl_return->push_back(convertSensorInfo(dst));
|
||||
}
|
||||
return ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ScopedAStatus HalProxyAidl::initialize(
|
||||
const MQDescriptor<::aidl::android::hardware::sensors::Event,
|
||||
SynchronizedReadWrite> &in_eventQueueDescriptor,
|
||||
const MQDescriptor<int32_t, SynchronizedReadWrite> &in_wakeLockDescriptor,
|
||||
const std::shared_ptr<ISensorsCallback> &in_sensorsCallback) {
|
||||
::android::sp<::android::hardware::sensors::V2_1::implementation::
|
||||
ISensorsCallbackWrapperBase>
|
||||
dynamicCallback = new ISensorsCallbackWrapperAidl(in_sensorsCallback);
|
||||
|
||||
auto aidlEventQueue = std::make_unique<::android::AidlMessageQueue<
|
||||
::aidl::android::hardware::sensors::Event, SynchronizedReadWrite>>(
|
||||
in_eventQueueDescriptor, true /* resetPointers */);
|
||||
std::unique_ptr<::android::hardware::sensors::V2_1::implementation::
|
||||
EventMessageQueueWrapperBase>
|
||||
eventQueue =
|
||||
std::make_unique<EventMessageQueueWrapperAidl>(aidlEventQueue);
|
||||
|
||||
auto aidlWakeLockQueue = std::make_unique<
|
||||
::android::AidlMessageQueue<int32_t, SynchronizedReadWrite>>(
|
||||
in_wakeLockDescriptor, true /* resetPointers */);
|
||||
std::unique_ptr<::android::hardware::sensors::V2_1::implementation::
|
||||
WakeLockMessageQueueWrapperBase>
|
||||
wakeLockQueue =
|
||||
std::make_unique<WakeLockMessageQueueWrapperAidl>(aidlWakeLockQueue);
|
||||
|
||||
return resultToAStatus(
|
||||
initializeCommon(eventQueue, wakeLockQueue, dynamicCallback));
|
||||
}
|
||||
|
||||
ScopedAStatus HalProxyAidl::injectSensorData(
|
||||
const ::aidl::android::hardware::sensors::Event &in_event) {
|
||||
::android::hardware::sensors::V2_1::Event hidlEvent;
|
||||
convertToHidlEvent(in_event, &hidlEvent);
|
||||
return resultToAStatus(
|
||||
HalProxy::injectSensorData(convertToOldEvent(hidlEvent)));
|
||||
}
|
||||
|
||||
ScopedAStatus
|
||||
HalProxyAidl::registerDirectChannel(const ISensors::SharedMemInfo &in_mem,
|
||||
int32_t *_aidl_return) {
|
||||
ScopedAStatus status =
|
||||
ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
::android::hardware::sensors::V1_0::SharedMemInfo sharedMemInfo =
|
||||
convertSharedMemInfo(in_mem);
|
||||
|
||||
HalProxy::registerDirectChannel(
|
||||
sharedMemInfo,
|
||||
[&status, _aidl_return](::android::hardware::sensors::V1_0::Result result,
|
||||
int32_t reportToken) {
|
||||
status = resultToAStatus(result);
|
||||
*_aidl_return = reportToken;
|
||||
});
|
||||
|
||||
native_handle_delete(const_cast<native_handle_t *>(
|
||||
sharedMemInfo.memoryHandle.getNativeHandle()));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
ScopedAStatus HalProxyAidl::setOperationMode(
|
||||
::aidl::android::hardware::sensors::ISensors::OperationMode in_mode) {
|
||||
return resultToAStatus(
|
||||
HalProxy::setOperationMode(convertOperationMode(in_mode)));
|
||||
}
|
||||
|
||||
ScopedAStatus HalProxyAidl::unregisterDirectChannel(int32_t in_channelHandle) {
|
||||
return resultToAStatus(HalProxy::unregisterDirectChannel(in_channelHandle));
|
||||
}
|
||||
|
||||
binder_status_t HalProxyAidl::dump(int fd, const char ** /* args */,
|
||||
uint32_t /* numArgs */) {
|
||||
native_handle_t *nativeHandle =
|
||||
native_handle_create(1 /* numFds */, 0 /* numInts */);
|
||||
nativeHandle->data[0] = fd;
|
||||
|
||||
HalProxy::debug(nativeHandle, {} /* args */);
|
||||
|
||||
native_handle_delete(nativeHandle);
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace sensors
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
53
aidl/sensors/HalProxySamsung.cpp
Normal file
53
aidl/sensors/HalProxySamsung.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The LineageOS Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "HalProxySamsung.h"
|
||||
|
||||
#include <ConvertUtils.h>
|
||||
|
||||
// #define VERBOSE
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace sensors {
|
||||
namespace implementation {
|
||||
|
||||
ndk::ScopedAStatus HalProxySamsung::getSensorsList(
|
||||
std::vector<::aidl::android::hardware::sensors::SensorInfo>* _aidl_return) {
|
||||
for (const auto& sensor : HalProxy::getSensors()) {
|
||||
SensorInfo dst = sensor.second;
|
||||
|
||||
if (dst.requiredPermission == "com.samsung.permission.SSENSOR") {
|
||||
dst.requiredPermission = "";
|
||||
}
|
||||
|
||||
if (dst.typeAsString == "com.samsung.sensor.physical_proximity" ||
|
||||
dst.typeAsString == "com.samsung.sensor.hover_proximity") {
|
||||
ALOGI("Fixing %s", dst.typeAsString.c_str());
|
||||
dst.type = ::android::hardware::sensors::V2_1::SensorType::PROXIMITY;
|
||||
dst.typeAsString = SENSOR_STRING_TYPE_PROXIMITY;
|
||||
dst.maxRange = 1;
|
||||
}
|
||||
|
||||
#ifdef VERBOSE
|
||||
ALOGI("SENSOR NAME:%s ", dst.name.c_str());
|
||||
ALOGI(" VENDOR:%s ", dst.name.c_str());
|
||||
ALOGI(" TYPE:%d ", (uint32_t)dst.type);
|
||||
ALOGI(" TYPE_AS_STRING:%s ", dst.typeAsString.c_str());
|
||||
#endif
|
||||
|
||||
_aidl_return->push_back(convertSensorInfo(dst));
|
||||
}
|
||||
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace sensors
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
26
aidl/sensors/HalProxySamsung.h
Normal file
26
aidl/sensors/HalProxySamsung.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The LineageOS Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <HalProxyAidl.h>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace sensors {
|
||||
namespace implementation {
|
||||
|
||||
class HalProxySamsung : public HalProxyAidl {
|
||||
ndk::ScopedAStatus getSensorsList(
|
||||
std::vector<::aidl::android::hardware::sensors::SensorInfo>* _aidl_return) override;
|
||||
};
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace sensors
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -17,7 +17,7 @@
|
||||
<manifest version="1.0" type="device">
|
||||
<hal format="aidl" override="true">
|
||||
<name>android.hardware.sensors</name>
|
||||
<version>1</version>
|
||||
<version>2</version>
|
||||
<fqname>ISensors/default</fqname>
|
||||
</hal>
|
||||
</manifest>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
service vendor.sensors-hal-multihal /vendor/bin/hw/android.hardware.sensors-service.samsung-multihal
|
||||
class hal
|
||||
user system
|
||||
group system wakelock context_hub input
|
||||
group system wakelock context_hub input uhid
|
||||
task_profiles ServiceCapacityLow
|
||||
capabilities BLOCK_SUSPEND
|
||||
rlimit rtprio 10 10
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <aidl/android/hardware/sensors/BnSensors.h>
|
||||
#include <android/hardware/sensors/2.1/types.h>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace sensors {
|
||||
namespace implementation {
|
||||
|
||||
/**
|
||||
* Generates an AIDL SensorInfo instance from the passed HIDL V2.1 SensorInfo instance.
|
||||
*/
|
||||
::aidl::android::hardware::sensors::SensorInfo convertSensorInfo(
|
||||
const ::android::hardware::sensors::V2_1::SensorInfo& sensorInfo);
|
||||
|
||||
/**
|
||||
* Populates a HIDL V2.1 Event instance based on an AIDL Event instance.
|
||||
*/
|
||||
void convertToHidlEvent(const ::aidl::android::hardware::sensors::Event& aidlEvent,
|
||||
::android::hardware::sensors::V2_1::Event* hidlEvent);
|
||||
|
||||
/**
|
||||
* Populates an AIDL Event instance based on a HIDL V2.1 Event instance.
|
||||
*/
|
||||
void convertToAidlEvent(const ::android::hardware::sensors::V2_1::Event& hidlEvent,
|
||||
::aidl::android::hardware::sensors::Event* aidlEvent);
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace sensors
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <android/hardware/sensors/2.1/types.h>
|
||||
#include <fmq/AidlMessageQueue.h>
|
||||
#include "ConvertUtils.h"
|
||||
#include "EventMessageQueueWrapper.h"
|
||||
#include "ISensorsWrapper.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace sensors {
|
||||
namespace implementation {
|
||||
|
||||
class EventMessageQueueWrapperAidl
|
||||
: public ::android::hardware::sensors::V2_1::implementation::EventMessageQueueWrapperBase {
|
||||
public:
|
||||
EventMessageQueueWrapperAidl(
|
||||
std::unique_ptr<::android::AidlMessageQueue<
|
||||
::aidl::android::hardware::sensors::Event,
|
||||
::aidl::android::hardware::common::fmq::SynchronizedReadWrite>>& queue)
|
||||
: mQueue(std::move(queue)) {}
|
||||
|
||||
virtual std::atomic<uint32_t>* getEventFlagWord() override {
|
||||
return mQueue->getEventFlagWord();
|
||||
}
|
||||
|
||||
virtual size_t availableToRead() override { return mQueue->availableToRead(); }
|
||||
|
||||
size_t availableToWrite() override { return mQueue->availableToWrite(); }
|
||||
|
||||
virtual bool read(::android::hardware::sensors::V2_1::Event* events,
|
||||
size_t numToRead) override {
|
||||
bool success = mQueue->read(mIntermediateEventBuffer.data(), numToRead);
|
||||
for (int i = 0; i < numToRead; ++i) {
|
||||
convertToHidlEvent(mIntermediateEventBuffer[i], &events[i]);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool write(const ::android::hardware::sensors::V2_1::Event* events,
|
||||
size_t numToWrite) override {
|
||||
for (int i = 0; i < numToWrite; ++i) {
|
||||
convertToAidlEvent(events[i], &mIntermediateEventBuffer[i]);
|
||||
}
|
||||
return mQueue->write(mIntermediateEventBuffer.data(), numToWrite);
|
||||
}
|
||||
|
||||
virtual bool write(
|
||||
const std::vector<::android::hardware::sensors::V2_1::Event>& events) override {
|
||||
for (int i = 0; i < events.size(); ++i) {
|
||||
convertToAidlEvent(events[i], &mIntermediateEventBuffer[i]);
|
||||
}
|
||||
return mQueue->write(mIntermediateEventBuffer.data(), events.size());
|
||||
}
|
||||
|
||||
bool writeBlocking(const ::android::hardware::sensors::V2_1::Event* events, size_t count,
|
||||
uint32_t readNotification, uint32_t writeNotification, int64_t timeOutNanos,
|
||||
::android::hardware::EventFlag* evFlag) override {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
convertToAidlEvent(events[i], &mIntermediateEventBuffer[i]);
|
||||
}
|
||||
return mQueue->writeBlocking(mIntermediateEventBuffer.data(), count, readNotification,
|
||||
writeNotification, timeOutNanos, evFlag);
|
||||
}
|
||||
|
||||
size_t getQuantumCount() override { return mQueue->getQuantumCount(); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<::android::AidlMessageQueue<
|
||||
::aidl::android::hardware::sensors::Event,
|
||||
::aidl::android::hardware::common::fmq::SynchronizedReadWrite>>
|
||||
mQueue;
|
||||
std::array<::aidl::android::hardware::sensors::Event,
|
||||
::android::hardware::sensors::V2_1::implementation::MAX_RECEIVE_BUFFER_EVENT_COUNT>
|
||||
mIntermediateEventBuffer;
|
||||
};
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace sensors
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <aidl/android/hardware/sensors/BnSensors.h>
|
||||
#include "HalProxy.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace sensors {
|
||||
namespace implementation {
|
||||
|
||||
class HalProxyAidl : public ::android::hardware::sensors::V2_1::implementation::HalProxy,
|
||||
public ::aidl::android::hardware::sensors::BnSensors {
|
||||
::ndk::ScopedAStatus activate(int32_t in_sensorHandle, bool in_enabled) override;
|
||||
::ndk::ScopedAStatus batch(int32_t in_sensorHandle, int64_t in_samplingPeriodNs,
|
||||
int64_t in_maxReportLatencyNs) override;
|
||||
::ndk::ScopedAStatus configDirectReport(
|
||||
int32_t in_sensorHandle, int32_t in_channelHandle,
|
||||
::aidl::android::hardware::sensors::ISensors::RateLevel in_rate,
|
||||
int32_t* _aidl_return) override;
|
||||
::ndk::ScopedAStatus flush(int32_t in_sensorHandle) override;
|
||||
::ndk::ScopedAStatus getSensorsList(
|
||||
std::vector<::aidl::android::hardware::sensors::SensorInfo>* _aidl_return) override;
|
||||
::ndk::ScopedAStatus initialize(
|
||||
const ::aidl::android::hardware::common::fmq::MQDescriptor<
|
||||
::aidl::android::hardware::sensors::Event,
|
||||
::aidl::android::hardware::common::fmq::SynchronizedReadWrite>&
|
||||
in_eventQueueDescriptor,
|
||||
const ::aidl::android::hardware::common::fmq::MQDescriptor<
|
||||
int32_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>&
|
||||
in_wakeLockDescriptor,
|
||||
const std::shared_ptr<::aidl::android::hardware::sensors::ISensorsCallback>&
|
||||
in_sensorsCallback) override;
|
||||
::ndk::ScopedAStatus injectSensorData(
|
||||
const ::aidl::android::hardware::sensors::Event& in_event) override;
|
||||
::ndk::ScopedAStatus registerDirectChannel(
|
||||
const ::aidl::android::hardware::sensors::ISensors::SharedMemInfo& in_mem,
|
||||
int32_t* _aidl_return) override;
|
||||
::ndk::ScopedAStatus setOperationMode(
|
||||
::aidl::android::hardware::sensors::ISensors::OperationMode in_mode) override;
|
||||
::ndk::ScopedAStatus unregisterDirectChannel(int32_t in_channelHandle) override;
|
||||
|
||||
binder_status_t dump(int fd, const char **args, uint32_t numArgs) override;
|
||||
};
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace sensors
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ConvertUtils.h"
|
||||
#include "ISensorsCallbackWrapper.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace sensors {
|
||||
namespace implementation {
|
||||
|
||||
static std::vector<::aidl::android::hardware::sensors::SensorInfo> convertToAidlSensorInfos(
|
||||
const ::android::hardware::hidl_vec<::android::hardware::sensors::V2_1::SensorInfo>&
|
||||
sensorInfos) {
|
||||
std::vector<::aidl::android::hardware::sensors::SensorInfo> aidlSensorInfos;
|
||||
for (const auto& sensorInfo : sensorInfos) {
|
||||
aidlSensorInfos.push_back(convertSensorInfo(sensorInfo));
|
||||
}
|
||||
return aidlSensorInfos;
|
||||
}
|
||||
|
||||
class ISensorsCallbackWrapperAidl
|
||||
: public ::android::hardware::sensors::V2_1::implementation::ISensorsCallbackWrapperBase {
|
||||
public:
|
||||
ISensorsCallbackWrapperAidl(
|
||||
std::shared_ptr<::aidl::android::hardware::sensors::ISensorsCallback> sensorsCallback)
|
||||
: mSensorsCallback(sensorsCallback) {}
|
||||
|
||||
::android::hardware::Return<void> onDynamicSensorsConnected(
|
||||
const ::android::hardware::hidl_vec<::android::hardware::sensors::V2_1::SensorInfo>&
|
||||
sensorInfos) override {
|
||||
mSensorsCallback->onDynamicSensorsConnected(convertToAidlSensorInfos(sensorInfos));
|
||||
return ::android::hardware::Void();
|
||||
}
|
||||
|
||||
::android::hardware::Return<void> onDynamicSensorsDisconnected(
|
||||
const ::android::hardware::hidl_vec<int32_t>& sensorHandles) override {
|
||||
mSensorsCallback->onDynamicSensorsDisconnected(sensorHandles);
|
||||
return ::android::hardware::Void();
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<::aidl::android::hardware::sensors::ISensorsCallback> mSensorsCallback;
|
||||
};
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace sensors
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <android/hardware/sensors/2.1/types.h>
|
||||
#include <fmq/AidlMessageQueue.h>
|
||||
#include "WakeLockMessageQueueWrapper.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace sensors {
|
||||
namespace implementation {
|
||||
|
||||
class WakeLockMessageQueueWrapperAidl
|
||||
: public ::android::hardware::sensors::V2_1::implementation::WakeLockMessageQueueWrapperBase {
|
||||
public:
|
||||
WakeLockMessageQueueWrapperAidl(
|
||||
std::unique_ptr<::android::AidlMessageQueue<
|
||||
int32_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>>& queue)
|
||||
: mQueue(std::move(queue)) {}
|
||||
|
||||
virtual std::atomic<uint32_t>* getEventFlagWord() override {
|
||||
return mQueue->getEventFlagWord();
|
||||
}
|
||||
|
||||
bool readBlocking(uint32_t* wakeLocks, size_t numToRead, uint32_t readNotification,
|
||||
uint32_t writeNotification, int64_t timeOutNanos,
|
||||
::android::hardware::EventFlag* evFlag) override {
|
||||
return mQueue->readBlocking(reinterpret_cast<int32_t*>(wakeLocks), numToRead,
|
||||
readNotification, writeNotification, timeOutNanos, evFlag);
|
||||
}
|
||||
|
||||
bool write(const uint32_t* wakeLock) override {
|
||||
return mQueue->write(reinterpret_cast<const int32_t*>(wakeLock));
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<::android::AidlMessageQueue<
|
||||
int32_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>>
|
||||
mQueue;
|
||||
};
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace sensors
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -17,16 +17,17 @@
|
||||
#include <android-base/logging.h>
|
||||
#include <android/binder_manager.h>
|
||||
#include <android/binder_process.h>
|
||||
#include "HalProxyAidl.h"
|
||||
|
||||
using ::aidl::android::hardware::sensors::implementation::HalProxyAidl;
|
||||
#include "HalProxySamsung.h"
|
||||
|
||||
using ::aidl::android::hardware::sensors::implementation::HalProxySamsung;
|
||||
|
||||
int main() {
|
||||
ABinderProcess_setThreadPoolMaxThreadCount(0);
|
||||
|
||||
// Make a default multihal sensors service
|
||||
auto halProxy = ndk::SharedRefBase::make<HalProxyAidl>();
|
||||
const std::string halProxyName = std::string() + HalProxyAidl::descriptor + "/default";
|
||||
auto halProxy = ndk::SharedRefBase::make<HalProxySamsung>();
|
||||
const std::string halProxyName = std::string() + HalProxySamsung::descriptor + "/default";
|
||||
binder_status_t status =
|
||||
AServiceManager_addService(halProxy->asBinder().get(), halProxyName.c_str());
|
||||
CHECK_EQ(status, STATUS_OK);
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
cc_binary {
|
||||
name: "android.hardware.thermal-service.samsung",
|
||||
srcs: [
|
||||
"service.cpp",
|
||||
"Thermal.cpp",
|
||||
"thermal-helper.cpp",
|
||||
"utils/thermal_throttling.cpp",
|
||||
"utils/thermal_info.cpp",
|
||||
"utils/thermal_files.cpp",
|
||||
"utils/power_files.cpp",
|
||||
"utils/powerhal_helper.cpp",
|
||||
"utils/thermal_watcher.cpp",
|
||||
],
|
||||
vendor: true,
|
||||
relative_install_path: "hw",
|
||||
vintf_fragments: [
|
||||
"android.hardware.thermal-service.samsung.xml"
|
||||
],
|
||||
init_rc: [
|
||||
"android.hardware.thermal-service.samsung.rc",
|
||||
],
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"libcutils",
|
||||
"libjsoncpp",
|
||||
"libutils",
|
||||
"libnl",
|
||||
"libbinder_ndk",
|
||||
"android.hardware.power-V1-ndk",
|
||||
"android.hardware.thermal-V1-ndk",
|
||||
"pixel-power-ext-V1-ndk",
|
||||
],
|
||||
static_libs: [
|
||||
"libpixelstats",
|
||||
],
|
||||
cflags: [
|
||||
"-Wall",
|
||||
"-Werror",
|
||||
"-Wextra",
|
||||
"-Wunused",
|
||||
],
|
||||
tidy: true,
|
||||
tidy_checks: [
|
||||
"android-*",
|
||||
"cert-*",
|
||||
"clang-analyzer-security*",
|
||||
],
|
||||
tidy_checks_as_errors: [
|
||||
"android-*",
|
||||
"clang-analyzer-security*",
|
||||
"cert-*",
|
||||
],
|
||||
}
|
||||
|
||||
sh_binary {
|
||||
name: "thermal_logd.samsung",
|
||||
src: "init.thermal.logging.sh",
|
||||
vendor: true,
|
||||
init_rc: [
|
||||
"samsung-thermal-logd.rc",
|
||||
],
|
||||
}
|
||||
|
||||
sh_binary {
|
||||
name: "thermal_symlinks.samsung",
|
||||
src: "init.thermal.symlinks.sh",
|
||||
vendor: true,
|
||||
init_rc: [
|
||||
"samsung-thermal-symlinks.rc",
|
||||
],
|
||||
}
|
||||
@@ -1,716 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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_THERMAL | ATRACE_TAG_HAL)
|
||||
|
||||
#include "Thermal.h"
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <utils/Trace.h>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace thermal {
|
||||
namespace implementation {
|
||||
|
||||
namespace {
|
||||
|
||||
using std::chrono::system_clock;
|
||||
|
||||
ndk::ScopedAStatus initErrorStatus() {
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
|
||||
"ThermalHAL not initialized properly.");
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus readErrorStatus() {
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
|
||||
EX_ILLEGAL_STATE, "ThermalHal cannot read any sensor data");
|
||||
}
|
||||
|
||||
bool interfacesEqual(const std::shared_ptr<::ndk::ICInterface> left,
|
||||
const std::shared_ptr<::ndk::ICInterface> right) {
|
||||
if (left == nullptr || right == nullptr || !left->isRemote() || !right->isRemote()) {
|
||||
return left == right;
|
||||
}
|
||||
return left->asBinder() == right->asBinder();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Thermal::Thermal()
|
||||
: thermal_helper_(
|
||||
std::bind(&Thermal::sendThermalChangedCallback, this, std::placeholders::_1)) {}
|
||||
|
||||
ndk::ScopedAStatus Thermal::getTemperatures(std::vector<Temperature> *_aidl_return) {
|
||||
return getFilteredTemperatures(false, TemperatureType::UNKNOWN, _aidl_return);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Thermal::getTemperaturesWithType(TemperatureType type,
|
||||
std::vector<Temperature> *_aidl_return) {
|
||||
return getFilteredTemperatures(true, type, _aidl_return);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Thermal::getFilteredTemperatures(bool filterType, TemperatureType type,
|
||||
std::vector<Temperature> *_aidl_return) {
|
||||
*_aidl_return = {};
|
||||
if (!thermal_helper_.isInitializedOk()) {
|
||||
return initErrorStatus();
|
||||
}
|
||||
if (!thermal_helper_.fillCurrentTemperatures(filterType, false, type, _aidl_return)) {
|
||||
return readErrorStatus();
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Thermal::getCoolingDevices(std::vector<CoolingDevice> *_aidl_return) {
|
||||
return getFilteredCoolingDevices(false, CoolingType::BATTERY, _aidl_return);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Thermal::getCoolingDevicesWithType(CoolingType type,
|
||||
std::vector<CoolingDevice> *_aidl_return) {
|
||||
return getFilteredCoolingDevices(true, type, _aidl_return);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Thermal::getFilteredCoolingDevices(bool filterType, CoolingType type,
|
||||
std::vector<CoolingDevice> *_aidl_return) {
|
||||
*_aidl_return = {};
|
||||
if (!thermal_helper_.isInitializedOk()) {
|
||||
return initErrorStatus();
|
||||
}
|
||||
if (!thermal_helper_.fillCurrentCoolingDevices(filterType, type, _aidl_return)) {
|
||||
return readErrorStatus();
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Thermal::getTemperatureThresholds(
|
||||
std::vector<TemperatureThreshold> *_aidl_return) {
|
||||
*_aidl_return = {};
|
||||
return getFilteredTemperatureThresholds(false, TemperatureType::UNKNOWN, _aidl_return);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Thermal::getTemperatureThresholdsWithType(
|
||||
TemperatureType type, std::vector<TemperatureThreshold> *_aidl_return) {
|
||||
return getFilteredTemperatureThresholds(true, type, _aidl_return);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Thermal::getFilteredTemperatureThresholds(
|
||||
bool filterType, TemperatureType type, std::vector<TemperatureThreshold> *_aidl_return) {
|
||||
*_aidl_return = {};
|
||||
if (!thermal_helper_.isInitializedOk()) {
|
||||
return initErrorStatus();
|
||||
}
|
||||
if (!thermal_helper_.fillTemperatureThresholds(filterType, type, _aidl_return)) {
|
||||
return readErrorStatus();
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Thermal::registerThermalChangedCallback(
|
||||
const std::shared_ptr<IThermalChangedCallback> &callback) {
|
||||
ATRACE_CALL();
|
||||
return registerThermalChangedCallback(callback, false, TemperatureType::UNKNOWN);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Thermal::registerThermalChangedCallbackWithType(
|
||||
const std::shared_ptr<IThermalChangedCallback> &callback, TemperatureType type) {
|
||||
ATRACE_CALL();
|
||||
return registerThermalChangedCallback(callback, true, type);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Thermal::unregisterThermalChangedCallback(
|
||||
const std::shared_ptr<IThermalChangedCallback> &callback) {
|
||||
if (callback == nullptr) {
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
|
||||
"Invalid nullptr callback");
|
||||
}
|
||||
bool removed = false;
|
||||
std::lock_guard<std::mutex> _lock(thermal_callback_mutex_);
|
||||
callbacks_.erase(
|
||||
std::remove_if(
|
||||
callbacks_.begin(), callbacks_.end(),
|
||||
[&](const CallbackSetting &c) {
|
||||
if (interfacesEqual(c.callback, callback)) {
|
||||
LOG(INFO)
|
||||
<< "a callback has been unregistered to ThermalHAL, isFilter: "
|
||||
<< c.is_filter_type << " Type: " << toString(c.type);
|
||||
removed = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
callbacks_.end());
|
||||
if (!removed) {
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
|
||||
"Callback wasn't registered");
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Thermal::registerThermalChangedCallback(
|
||||
const std::shared_ptr<IThermalChangedCallback> &callback, bool filterType,
|
||||
TemperatureType type) {
|
||||
ATRACE_CALL();
|
||||
if (callback == nullptr) {
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
|
||||
"Invalid nullptr callback");
|
||||
}
|
||||
if (!thermal_helper_.isInitializedOk()) {
|
||||
return initErrorStatus();
|
||||
}
|
||||
std::lock_guard<std::mutex> _lock(thermal_callback_mutex_);
|
||||
if (std::any_of(callbacks_.begin(), callbacks_.end(), [&](const CallbackSetting &c) {
|
||||
return interfacesEqual(c.callback, callback);
|
||||
})) {
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
|
||||
"Callback already registered");
|
||||
}
|
||||
auto c = callbacks_.emplace_back(callback, filterType, type);
|
||||
LOG(INFO) << "a callback has been registered to ThermalHAL, isFilter: " << c.is_filter_type
|
||||
<< " Type: " << toString(c.type);
|
||||
// Send notification right away after successful thermal callback registration
|
||||
std::function<void()> handler = [this, c, filterType, type]() {
|
||||
std::vector<Temperature> temperatures;
|
||||
if (thermal_helper_.fillCurrentTemperatures(filterType, true, type, &temperatures)) {
|
||||
for (const auto &t : temperatures) {
|
||||
if (!filterType || t.type == type) {
|
||||
LOG(INFO) << "Sending notification: "
|
||||
<< " Type: " << toString(t.type) << " Name: " << t.name
|
||||
<< " CurrentValue: " << t.value
|
||||
<< " ThrottlingStatus: " << toString(t.throttlingStatus);
|
||||
c.callback->notifyThrottling(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
looper_.addEvent(Looper::Event{handler});
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
void Thermal::sendThermalChangedCallback(const Temperature &t) {
|
||||
ATRACE_CALL();
|
||||
std::lock_guard<std::mutex> _lock(thermal_callback_mutex_);
|
||||
LOG(VERBOSE) << "Sending notification: "
|
||||
<< " Type: " << toString(t.type) << " Name: " << t.name
|
||||
<< " CurrentValue: " << t.value
|
||||
<< " ThrottlingStatus: " << toString(t.throttlingStatus);
|
||||
|
||||
callbacks_.erase(std::remove_if(callbacks_.begin(), callbacks_.end(),
|
||||
[&](const CallbackSetting &c) {
|
||||
if (!c.is_filter_type || t.type == c.type) {
|
||||
::ndk::ScopedAStatus ret =
|
||||
c.callback->notifyThrottling(t);
|
||||
if (!ret.isOk()) {
|
||||
LOG(ERROR) << "a Thermal callback is dead, removed "
|
||||
"from callback list.";
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
callbacks_.end());
|
||||
}
|
||||
|
||||
void Thermal::dumpVirtualSensorInfo(std::ostringstream *dump_buf) {
|
||||
*dump_buf << "getVirtualSensorInfo:" << std::endl;
|
||||
const auto &map = thermal_helper_.GetSensorInfoMap();
|
||||
for (const auto &sensor_info_pair : map) {
|
||||
if (sensor_info_pair.second.virtual_sensor_info != nullptr) {
|
||||
*dump_buf << " Name: " << sensor_info_pair.first << std::endl;
|
||||
*dump_buf << " LinkedSensorName: [";
|
||||
for (size_t i = 0;
|
||||
i < sensor_info_pair.second.virtual_sensor_info->linked_sensors.size(); i++) {
|
||||
*dump_buf << sensor_info_pair.second.virtual_sensor_info->linked_sensors[i] << " ";
|
||||
}
|
||||
*dump_buf << "]" << std::endl;
|
||||
*dump_buf << " LinkedSensorCoefficient: [";
|
||||
for (size_t i = 0; i < sensor_info_pair.second.virtual_sensor_info->coefficients.size();
|
||||
i++) {
|
||||
*dump_buf << sensor_info_pair.second.virtual_sensor_info->coefficients[i] << " ";
|
||||
}
|
||||
*dump_buf << "]" << std::endl;
|
||||
*dump_buf << " Offset: " << sensor_info_pair.second.virtual_sensor_info->offset
|
||||
<< std::endl;
|
||||
*dump_buf << " Trigger Sensor: ";
|
||||
if (sensor_info_pair.second.virtual_sensor_info->trigger_sensors.empty()) {
|
||||
*dump_buf << "N/A" << std::endl;
|
||||
} else {
|
||||
for (size_t i = 0;
|
||||
i < sensor_info_pair.second.virtual_sensor_info->trigger_sensors.size(); i++) {
|
||||
*dump_buf << sensor_info_pair.second.virtual_sensor_info->trigger_sensors[i]
|
||||
<< " ";
|
||||
}
|
||||
*dump_buf << std::endl;
|
||||
}
|
||||
*dump_buf << " Formula: ";
|
||||
switch (sensor_info_pair.second.virtual_sensor_info->formula) {
|
||||
case FormulaOption::COUNT_THRESHOLD:
|
||||
*dump_buf << "COUNT_THRESHOLD";
|
||||
break;
|
||||
case FormulaOption::WEIGHTED_AVG:
|
||||
*dump_buf << "WEIGHTED_AVG";
|
||||
break;
|
||||
case FormulaOption::MAXIMUM:
|
||||
*dump_buf << "MAXIMUM";
|
||||
break;
|
||||
case FormulaOption::MINIMUM:
|
||||
*dump_buf << "MINIMUM";
|
||||
break;
|
||||
default:
|
||||
*dump_buf << "NONE";
|
||||
break;
|
||||
}
|
||||
|
||||
*dump_buf << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Thermal::dumpThrottlingInfo(std::ostringstream *dump_buf) {
|
||||
*dump_buf << "getThrottlingInfo:" << std::endl;
|
||||
const auto &map = thermal_helper_.GetSensorInfoMap();
|
||||
const auto &thermal_throttling_status_map = thermal_helper_.GetThermalThrottlingStatusMap();
|
||||
for (const auto &name_info_pair : map) {
|
||||
if (name_info_pair.second.throttling_info == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (name_info_pair.second.throttling_info->binded_cdev_info_map.size()) {
|
||||
if (thermal_throttling_status_map.find(name_info_pair.first) ==
|
||||
thermal_throttling_status_map.end()) {
|
||||
continue;
|
||||
}
|
||||
*dump_buf << " Name: " << name_info_pair.first << std::endl;
|
||||
if (thermal_throttling_status_map.at(name_info_pair.first)
|
||||
.pid_power_budget_map.size()) {
|
||||
*dump_buf << " PID Info:" << std::endl;
|
||||
*dump_buf << " K_po: [";
|
||||
for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
|
||||
*dump_buf << name_info_pair.second.throttling_info->k_po[i] << " ";
|
||||
}
|
||||
*dump_buf << "]" << std::endl;
|
||||
*dump_buf << " K_pu: [";
|
||||
for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
|
||||
*dump_buf << name_info_pair.second.throttling_info->k_pu[i] << " ";
|
||||
}
|
||||
*dump_buf << "]" << std::endl;
|
||||
*dump_buf << " K_i: [";
|
||||
for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
|
||||
*dump_buf << name_info_pair.second.throttling_info->k_i[i] << " ";
|
||||
}
|
||||
*dump_buf << "]" << std::endl;
|
||||
*dump_buf << " K_d: [";
|
||||
for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
|
||||
*dump_buf << name_info_pair.second.throttling_info->k_d[i] << " ";
|
||||
}
|
||||
*dump_buf << "]" << std::endl;
|
||||
*dump_buf << " i_max: [";
|
||||
for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
|
||||
*dump_buf << name_info_pair.second.throttling_info->i_max[i] << " ";
|
||||
}
|
||||
*dump_buf << "]" << std::endl;
|
||||
*dump_buf << " max_alloc_power: [";
|
||||
for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
|
||||
*dump_buf << name_info_pair.second.throttling_info->max_alloc_power[i] << " ";
|
||||
}
|
||||
*dump_buf << "]" << std::endl;
|
||||
*dump_buf << " min_alloc_power: [";
|
||||
for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
|
||||
*dump_buf << name_info_pair.second.throttling_info->min_alloc_power[i] << " ";
|
||||
}
|
||||
*dump_buf << "]" << std::endl;
|
||||
*dump_buf << " s_power: [";
|
||||
for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
|
||||
*dump_buf << name_info_pair.second.throttling_info->s_power[i] << " ";
|
||||
}
|
||||
*dump_buf << "]" << std::endl;
|
||||
*dump_buf << " i_cutoff: [";
|
||||
for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
|
||||
*dump_buf << name_info_pair.second.throttling_info->i_cutoff[i] << " ";
|
||||
}
|
||||
*dump_buf << "]" << std::endl;
|
||||
}
|
||||
*dump_buf << " Binded CDEV Info:" << std::endl;
|
||||
for (const auto &binded_cdev_info_pair :
|
||||
name_info_pair.second.throttling_info->binded_cdev_info_map) {
|
||||
*dump_buf << " Cooling device name: " << binded_cdev_info_pair.first << std::endl;
|
||||
if (thermal_throttling_status_map.at(name_info_pair.first)
|
||||
.pid_power_budget_map.size()) {
|
||||
*dump_buf << " WeightForPID: [";
|
||||
for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
|
||||
*dump_buf << binded_cdev_info_pair.second.cdev_weight_for_pid[i] << " ";
|
||||
}
|
||||
*dump_buf << "]" << std::endl;
|
||||
}
|
||||
*dump_buf << " Ceiling: [";
|
||||
for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
|
||||
*dump_buf << binded_cdev_info_pair.second.cdev_ceiling[i] << " ";
|
||||
}
|
||||
*dump_buf << "]" << std::endl;
|
||||
*dump_buf << " Hard limit: [";
|
||||
for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
|
||||
*dump_buf << binded_cdev_info_pair.second.limit_info[i] << " ";
|
||||
}
|
||||
*dump_buf << "]" << std::endl;
|
||||
|
||||
if (!binded_cdev_info_pair.second.power_rail.empty()) {
|
||||
*dump_buf << " Binded power rail: "
|
||||
<< binded_cdev_info_pair.second.power_rail << std::endl;
|
||||
*dump_buf << " Power threshold: [";
|
||||
for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
|
||||
*dump_buf << binded_cdev_info_pair.second.power_thresholds[i] << " ";
|
||||
}
|
||||
*dump_buf << "]" << std::endl;
|
||||
*dump_buf << " Floor with PowerLink: [";
|
||||
for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
|
||||
*dump_buf << binded_cdev_info_pair.second.cdev_floor_with_power_link[i]
|
||||
<< " ";
|
||||
}
|
||||
*dump_buf << "]" << std::endl;
|
||||
*dump_buf << " Release logic: ";
|
||||
switch (binded_cdev_info_pair.second.release_logic) {
|
||||
case ReleaseLogic::INCREASE:
|
||||
*dump_buf << "INCREASE";
|
||||
break;
|
||||
case ReleaseLogic::DECREASE:
|
||||
*dump_buf << "DECREASE";
|
||||
break;
|
||||
case ReleaseLogic::STEPWISE:
|
||||
*dump_buf << "STEPWISE";
|
||||
break;
|
||||
case ReleaseLogic::RELEASE_TO_FLOOR:
|
||||
*dump_buf << "RELEASE_TO_FLOOR";
|
||||
break;
|
||||
default:
|
||||
*dump_buf << "NONE";
|
||||
break;
|
||||
}
|
||||
*dump_buf << std::endl;
|
||||
*dump_buf << " high_power_check: " << std::boolalpha
|
||||
<< binded_cdev_info_pair.second.high_power_check << std::endl;
|
||||
*dump_buf << " throttling_with_power_link: " << std::boolalpha
|
||||
<< binded_cdev_info_pair.second.throttling_with_power_link
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Thermal::dumpThrottlingRequestStatus(std::ostringstream *dump_buf) {
|
||||
const auto &thermal_throttling_status_map = thermal_helper_.GetThermalThrottlingStatusMap();
|
||||
if (!thermal_throttling_status_map.size()) {
|
||||
return;
|
||||
}
|
||||
*dump_buf << "getThrottlingRequestStatus:" << std::endl;
|
||||
for (const auto &thermal_throttling_status_pair : thermal_throttling_status_map) {
|
||||
*dump_buf << " Name: " << thermal_throttling_status_pair.first << std::endl;
|
||||
if (thermal_throttling_status_pair.second.pid_power_budget_map.size()) {
|
||||
*dump_buf << " power budget request state" << std::endl;
|
||||
for (const auto &request_pair :
|
||||
thermal_throttling_status_pair.second.pid_power_budget_map) {
|
||||
*dump_buf << " " << request_pair.first << ": " << request_pair.second
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
if (thermal_throttling_status_pair.second.pid_cdev_request_map.size()) {
|
||||
*dump_buf << " pid cdev request state" << std::endl;
|
||||
for (const auto &request_pair :
|
||||
thermal_throttling_status_pair.second.pid_cdev_request_map) {
|
||||
*dump_buf << " " << request_pair.first << ": " << request_pair.second
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
if (thermal_throttling_status_pair.second.hardlimit_cdev_request_map.size()) {
|
||||
*dump_buf << " hard limit cdev request state" << std::endl;
|
||||
for (const auto &request_pair :
|
||||
thermal_throttling_status_pair.second.hardlimit_cdev_request_map) {
|
||||
*dump_buf << " " << request_pair.first << ": " << request_pair.second
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
if (thermal_throttling_status_pair.second.throttling_release_map.size()) {
|
||||
*dump_buf << " cdev release state" << std::endl;
|
||||
for (const auto &request_pair :
|
||||
thermal_throttling_status_pair.second.throttling_release_map) {
|
||||
*dump_buf << " " << request_pair.first << ": " << request_pair.second
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
if (thermal_throttling_status_pair.second.cdev_status_map.size()) {
|
||||
*dump_buf << " cdev request state" << std::endl;
|
||||
for (const auto &request_pair : thermal_throttling_status_pair.second.cdev_status_map) {
|
||||
*dump_buf << " " << request_pair.first << ": " << request_pair.second
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Thermal::dumpPowerRailInfo(std::ostringstream *dump_buf) {
|
||||
const auto &power_rail_info_map = thermal_helper_.GetPowerRailInfoMap();
|
||||
const auto &power_status_map = thermal_helper_.GetPowerStatusMap();
|
||||
|
||||
*dump_buf << "getPowerRailInfo:" << std::endl;
|
||||
for (const auto &power_rail_pair : power_rail_info_map) {
|
||||
*dump_buf << " Power Rail: " << power_rail_pair.first << std::endl;
|
||||
*dump_buf << " Power Sample Count: " << power_rail_pair.second.power_sample_count
|
||||
<< std::endl;
|
||||
*dump_buf << " Power Sample Delay: " << power_rail_pair.second.power_sample_delay.count()
|
||||
<< std::endl;
|
||||
if (power_status_map.count(power_rail_pair.first)) {
|
||||
auto power_history = power_status_map.at(power_rail_pair.first).power_history;
|
||||
*dump_buf << " Last Updated AVG Power: "
|
||||
<< power_status_map.at(power_rail_pair.first).last_updated_avg_power << " mW"
|
||||
<< std::endl;
|
||||
if (power_rail_pair.second.virtual_power_rail_info != nullptr) {
|
||||
*dump_buf << " Formula=";
|
||||
switch (power_rail_pair.second.virtual_power_rail_info->formula) {
|
||||
case FormulaOption::COUNT_THRESHOLD:
|
||||
*dump_buf << "COUNT_THRESHOLD";
|
||||
break;
|
||||
case FormulaOption::WEIGHTED_AVG:
|
||||
*dump_buf << "WEIGHTED_AVG";
|
||||
break;
|
||||
case FormulaOption::MAXIMUM:
|
||||
*dump_buf << "MAXIMUM";
|
||||
break;
|
||||
case FormulaOption::MINIMUM:
|
||||
*dump_buf << "MINIMUM";
|
||||
break;
|
||||
default:
|
||||
*dump_buf << "NONE";
|
||||
break;
|
||||
}
|
||||
*dump_buf << std::endl;
|
||||
}
|
||||
for (size_t i = 0; i < power_history.size(); ++i) {
|
||||
if (power_rail_pair.second.virtual_power_rail_info != nullptr) {
|
||||
*dump_buf
|
||||
<< " Linked power rail "
|
||||
<< power_rail_pair.second.virtual_power_rail_info->linked_power_rails[i]
|
||||
<< std::endl;
|
||||
*dump_buf << " Coefficient="
|
||||
<< power_rail_pair.second.virtual_power_rail_info->coefficients[i]
|
||||
<< std::endl;
|
||||
*dump_buf << " Power Samples: ";
|
||||
} else {
|
||||
*dump_buf << " Power Samples: ";
|
||||
}
|
||||
while (power_history[i].size() > 0) {
|
||||
const auto power_sample = power_history[i].front();
|
||||
power_history[i].pop();
|
||||
*dump_buf << "(T=" << power_sample.duration
|
||||
<< ", uWs=" << power_sample.energy_counter << ") ";
|
||||
}
|
||||
*dump_buf << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Thermal::dumpThermalData(int fd) {
|
||||
std::ostringstream dump_buf;
|
||||
|
||||
if (!thermal_helper_.isInitializedOk()) {
|
||||
dump_buf << "ThermalHAL not initialized properly." << std::endl;
|
||||
} else {
|
||||
const auto &sensor_status_map = thermal_helper_.GetSensorStatusMap();
|
||||
{
|
||||
dump_buf << "getCachedTemperatures:" << std::endl;
|
||||
boot_clock::time_point now = boot_clock::now();
|
||||
for (const auto &sensor_status_pair : sensor_status_map) {
|
||||
if ((sensor_status_pair.second.thermal_cached.timestamp) ==
|
||||
boot_clock::time_point::min()) {
|
||||
continue;
|
||||
}
|
||||
dump_buf << " Name: " << sensor_status_pair.first
|
||||
<< " CachedValue: " << sensor_status_pair.second.thermal_cached.temp
|
||||
<< " TimeToCache: "
|
||||
<< std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
now - sensor_status_pair.second.thermal_cached.timestamp)
|
||||
.count()
|
||||
<< "ms" << std::endl;
|
||||
}
|
||||
}
|
||||
{
|
||||
dump_buf << "getEmulTemperatures:" << std::endl;
|
||||
for (const auto &sensor_status_pair : sensor_status_map) {
|
||||
if (sensor_status_pair.second.emul_setting == nullptr) {
|
||||
continue;
|
||||
}
|
||||
dump_buf << " Name: " << sensor_status_pair.first
|
||||
<< " EmulTemp: " << sensor_status_pair.second.emul_setting->emul_temp
|
||||
<< " EmulSeverity: "
|
||||
<< sensor_status_pair.second.emul_setting->emul_severity << std::endl;
|
||||
}
|
||||
}
|
||||
{
|
||||
const auto &map = thermal_helper_.GetSensorInfoMap();
|
||||
dump_buf << "getCurrentTemperatures:" << std::endl;
|
||||
Temperature temp_2_0;
|
||||
for (const auto &name_info_pair : map) {
|
||||
thermal_helper_.readTemperature(name_info_pair.first, &temp_2_0, nullptr, true);
|
||||
dump_buf << " Type: " << toString(temp_2_0.type)
|
||||
<< " Name: " << name_info_pair.first << " CurrentValue: " << temp_2_0.value
|
||||
<< " ThrottlingStatus: " << toString(temp_2_0.throttlingStatus)
|
||||
<< std::endl;
|
||||
}
|
||||
dump_buf << "getTemperatureThresholds:" << std::endl;
|
||||
for (const auto &name_info_pair : map) {
|
||||
if (!name_info_pair.second.is_watch) {
|
||||
continue;
|
||||
}
|
||||
dump_buf << " Type: " << toString(name_info_pair.second.type)
|
||||
<< " Name: " << name_info_pair.first;
|
||||
dump_buf << " hotThrottlingThreshold: [";
|
||||
for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
|
||||
dump_buf << name_info_pair.second.hot_thresholds[i] << " ";
|
||||
}
|
||||
dump_buf << "] coldThrottlingThreshold: [";
|
||||
for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
|
||||
dump_buf << name_info_pair.second.cold_thresholds[i] << " ";
|
||||
}
|
||||
dump_buf << "] vrThrottlingThreshold: " << name_info_pair.second.vr_threshold;
|
||||
dump_buf << std::endl;
|
||||
}
|
||||
dump_buf << "getHysteresis:" << std::endl;
|
||||
for (const auto &name_info_pair : map) {
|
||||
if (!name_info_pair.second.is_watch) {
|
||||
continue;
|
||||
}
|
||||
dump_buf << " Name: " << name_info_pair.first;
|
||||
dump_buf << " hotHysteresis: [";
|
||||
for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
|
||||
dump_buf << name_info_pair.second.hot_hysteresis[i] << " ";
|
||||
}
|
||||
dump_buf << "] coldHysteresis: [";
|
||||
for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
|
||||
dump_buf << name_info_pair.second.cold_hysteresis[i] << " ";
|
||||
}
|
||||
dump_buf << "]" << std::endl;
|
||||
}
|
||||
}
|
||||
{
|
||||
dump_buf << "getCurrentCoolingDevices:" << std::endl;
|
||||
std::vector<CoolingDevice> cooling_devices;
|
||||
if (!thermal_helper_.fillCurrentCoolingDevices(false, CoolingType::CPU,
|
||||
&cooling_devices)) {
|
||||
dump_buf << " Failed to getCurrentCoolingDevices." << std::endl;
|
||||
}
|
||||
|
||||
for (const auto &c : cooling_devices) {
|
||||
dump_buf << " Type: " << toString(c.type) << " Name: " << c.name
|
||||
<< " CurrentValue: " << c.value << std::endl;
|
||||
}
|
||||
}
|
||||
{
|
||||
dump_buf << "getCallbacks:" << std::endl;
|
||||
dump_buf << " Total: " << callbacks_.size() << std::endl;
|
||||
for (const auto &c : callbacks_) {
|
||||
dump_buf << " IsFilter: " << c.is_filter_type << " Type: " << toString(c.type)
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
{
|
||||
dump_buf << "sendCallback:" << std::endl;
|
||||
dump_buf << " Enabled List: ";
|
||||
const auto &map = thermal_helper_.GetSensorInfoMap();
|
||||
for (const auto &name_info_pair : map) {
|
||||
if (name_info_pair.second.send_cb) {
|
||||
dump_buf << name_info_pair.first << " ";
|
||||
}
|
||||
}
|
||||
dump_buf << std::endl;
|
||||
}
|
||||
{
|
||||
dump_buf << "sendPowerHint:" << std::endl;
|
||||
dump_buf << " Enabled List: ";
|
||||
const auto &map = thermal_helper_.GetSensorInfoMap();
|
||||
for (const auto &name_info_pair : map) {
|
||||
if (name_info_pair.second.send_powerhint) {
|
||||
dump_buf << name_info_pair.first << " ";
|
||||
}
|
||||
}
|
||||
dump_buf << std::endl;
|
||||
}
|
||||
dumpVirtualSensorInfo(&dump_buf);
|
||||
dumpThrottlingInfo(&dump_buf);
|
||||
dumpThrottlingRequestStatus(&dump_buf);
|
||||
dumpPowerRailInfo(&dump_buf);
|
||||
{
|
||||
dump_buf << "getAIDLPowerHalInfo:" << std::endl;
|
||||
dump_buf << " Exist: " << std::boolalpha << thermal_helper_.isAidlPowerHalExist()
|
||||
<< std::endl;
|
||||
dump_buf << " Connected: " << std::boolalpha << thermal_helper_.isPowerHalConnected()
|
||||
<< std::endl;
|
||||
dump_buf << " Ext connected: " << std::boolalpha
|
||||
<< thermal_helper_.isPowerHalExtConnected() << std::endl;
|
||||
}
|
||||
}
|
||||
std::string buf = dump_buf.str();
|
||||
if (!::android::base::WriteStringToFd(buf, fd)) {
|
||||
PLOG(ERROR) << "Failed to dump state to fd";
|
||||
}
|
||||
fsync(fd);
|
||||
}
|
||||
|
||||
binder_status_t Thermal::dump(int fd, const char **args, uint32_t numArgs) {
|
||||
if (numArgs == 0 || std::string(args[0]) == "-a") {
|
||||
dumpThermalData(fd);
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
if (std::string(args[0]) == "emul_temp") {
|
||||
return (numArgs != 3 || !thermal_helper_.emulTemp(std::string(args[1]), std::atof(args[2])))
|
||||
? STATUS_BAD_VALUE
|
||||
: STATUS_OK;
|
||||
} else if (std::string(args[0]) == "emul_severity") {
|
||||
return (numArgs != 3 ||
|
||||
!thermal_helper_.emulSeverity(std::string(args[1]), std::atoi(args[2])))
|
||||
? STATUS_BAD_VALUE
|
||||
: STATUS_OK;
|
||||
} else if (std::string(args[0]) == "emul_clear") {
|
||||
return (numArgs != 2 || !thermal_helper_.emulClear(std::string(args[1]))) ? STATUS_BAD_VALUE
|
||||
: STATUS_OK;
|
||||
}
|
||||
return STATUS_BAD_VALUE;
|
||||
}
|
||||
|
||||
void Thermal::Looper::addEvent(const Thermal::Looper::Event &e) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
events_.push(e);
|
||||
cv_.notify_all();
|
||||
}
|
||||
|
||||
void Thermal::Looper::loop() {
|
||||
while (true) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
cv_.wait(lock, [&] { return !events_.empty(); });
|
||||
Event event = events_.front();
|
||||
events_.pop();
|
||||
lock.unlock();
|
||||
event.handler();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace thermal
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <aidl/android/hardware/thermal/BnThermal.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include "thermal-helper.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace thermal {
|
||||
namespace implementation {
|
||||
|
||||
struct CallbackSetting {
|
||||
CallbackSetting(std::shared_ptr<IThermalChangedCallback> callback, bool is_filter_type,
|
||||
TemperatureType type)
|
||||
: callback(std::move(callback)), is_filter_type(is_filter_type), type(type) {}
|
||||
std::shared_ptr<IThermalChangedCallback> callback;
|
||||
bool is_filter_type;
|
||||
TemperatureType type;
|
||||
};
|
||||
|
||||
class Thermal : public BnThermal {
|
||||
public:
|
||||
Thermal();
|
||||
~Thermal() = default;
|
||||
ndk::ScopedAStatus getTemperatures(std::vector<Temperature> *_aidl_return) override;
|
||||
ndk::ScopedAStatus getTemperaturesWithType(TemperatureType type,
|
||||
std::vector<Temperature> *_aidl_return) override;
|
||||
|
||||
ndk::ScopedAStatus getCoolingDevices(std::vector<CoolingDevice> *_aidl_return) override;
|
||||
ndk::ScopedAStatus getCoolingDevicesWithType(CoolingType type,
|
||||
std::vector<CoolingDevice> *_aidl_return) override;
|
||||
|
||||
ndk::ScopedAStatus getTemperatureThresholds(
|
||||
std::vector<TemperatureThreshold> *_aidl_return) override;
|
||||
ndk::ScopedAStatus getTemperatureThresholdsWithType(
|
||||
TemperatureType type, std::vector<TemperatureThreshold> *_aidl_return) override;
|
||||
|
||||
ndk::ScopedAStatus registerThermalChangedCallback(
|
||||
const std::shared_ptr<IThermalChangedCallback> &callback) override;
|
||||
ndk::ScopedAStatus registerThermalChangedCallbackWithType(
|
||||
const std::shared_ptr<IThermalChangedCallback> &callback,
|
||||
TemperatureType type) override;
|
||||
ndk::ScopedAStatus unregisterThermalChangedCallback(
|
||||
const std::shared_ptr<IThermalChangedCallback> &callback) override;
|
||||
binder_status_t dump(int fd, const char **args, uint32_t numArgs) override;
|
||||
|
||||
// Helper function for calling callbacks
|
||||
void sendThermalChangedCallback(const Temperature &t);
|
||||
|
||||
private:
|
||||
class Looper {
|
||||
public:
|
||||
struct Event {
|
||||
std::function<void()> handler;
|
||||
};
|
||||
|
||||
Looper() {
|
||||
thread_ = std::thread([&] { loop(); });
|
||||
}
|
||||
void addEvent(const Event &e);
|
||||
|
||||
private:
|
||||
std::condition_variable cv_;
|
||||
std::queue<Event> events_;
|
||||
std::mutex mutex_;
|
||||
std::thread thread_;
|
||||
|
||||
void loop();
|
||||
};
|
||||
|
||||
ThermalHelper thermal_helper_;
|
||||
std::mutex thermal_callback_mutex_;
|
||||
std::vector<CallbackSetting> callbacks_;
|
||||
Looper looper_;
|
||||
|
||||
ndk::ScopedAStatus getFilteredTemperatures(bool filterType, TemperatureType type,
|
||||
std::vector<Temperature> *_aidl_return);
|
||||
ndk::ScopedAStatus getFilteredCoolingDevices(bool filterType, CoolingType type,
|
||||
std::vector<CoolingDevice> *_aidl_return);
|
||||
ndk::ScopedAStatus getFilteredTemperatureThresholds(
|
||||
bool filterType, TemperatureType type, std::vector<TemperatureThreshold> *_aidl_return);
|
||||
ndk::ScopedAStatus registerThermalChangedCallback(
|
||||
const std::shared_ptr<IThermalChangedCallback> &callback, bool filterType,
|
||||
TemperatureType type);
|
||||
|
||||
void dumpVirtualSensorInfo(std::ostringstream *dump_buf);
|
||||
void dumpThrottlingInfo(std::ostringstream *dump_buf);
|
||||
void dumpThrottlingRequestStatus(std::ostringstream *dump_buf);
|
||||
void dumpPowerRailInfo(std::ostringstream *dump_buf);
|
||||
void dumpThermalData(int fd);
|
||||
};
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace thermal
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -1,14 +0,0 @@
|
||||
on property:vendor.thermal.link_ready=1
|
||||
# queue the trigger to start thermal-hal and continue execute
|
||||
# per-device thermal setup "on property:vendor.thermal.link_ready=1"
|
||||
trigger enable-thermal-hal
|
||||
|
||||
on enable-thermal-hal
|
||||
restart vendor.thermal-hal
|
||||
|
||||
service vendor.thermal-hal /vendor/bin/hw/android.hardware.thermal-service.samsung
|
||||
class hal
|
||||
user system
|
||||
group system
|
||||
priority -20
|
||||
disabled
|
||||
@@ -1,7 +0,0 @@
|
||||
<manifest version="1.0" type="device">
|
||||
<hal format="aidl">
|
||||
<name>android.hardware.thermal</name>
|
||||
<version>1</version>
|
||||
<fqname>IThermal/default</fqname>
|
||||
</hal>
|
||||
</manifest>
|
||||
@@ -1,25 +0,0 @@
|
||||
#!/vendor/bin/sh
|
||||
|
||||
if [ $# -eq 1 ]; then
|
||||
interval=$1
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while true
|
||||
do
|
||||
logline="tz:"
|
||||
for f in /sys/class/thermal/thermal*
|
||||
do
|
||||
temp=`cat $f/temp`
|
||||
logline+="|$temp"
|
||||
done
|
||||
logline+=" cdev:"
|
||||
for f in /sys/class/thermal/cooling_device*
|
||||
do
|
||||
cur_state=`cat $f/cur_state`
|
||||
logline+="|$cur_state"
|
||||
done
|
||||
log -p w -t THERMAL_LOG $logline
|
||||
sleep $interval
|
||||
done
|
||||
@@ -1,13 +0,0 @@
|
||||
#!/vendor/bin/sh
|
||||
|
||||
for f in /sys/class/thermal/thermal_zone*
|
||||
do
|
||||
tz_name=`cat $f/type`
|
||||
ln -s $f /dev/thermal/tz-by-name/$tz_name
|
||||
done
|
||||
for f in /sys/class/thermal/cooling_device*
|
||||
do
|
||||
cdev_name=`cat $f/type`
|
||||
ln -s $f /dev/thermal/cdev-by-name/$cdev_name
|
||||
done
|
||||
setprop vendor.thermal.link_ready 1
|
||||
@@ -1,130 +0,0 @@
|
||||
on property:persist.vendor.log.thermal=1
|
||||
start vendor.thermal.logd
|
||||
|
||||
on property:persist.vendor.log.thermal=0
|
||||
stop vendor.thermal.logd
|
||||
|
||||
on property:persist.vendor.log.thermal=1 && property:persist.vendor.log.thermal.interval=*
|
||||
restart vendor.thermal.logd
|
||||
|
||||
service vendor.thermal.logd /vendor/bin/thermal_logd.samsung ${persist.vendor.log.thermal.interval:-5}
|
||||
class main
|
||||
user root
|
||||
group root system
|
||||
disabled
|
||||
|
||||
# Switch thermal protection for Pixels
|
||||
on property:persist.vendor.disable.thermal.control=*
|
||||
setprop vendor.disable.thermal.control ${persist.vendor.disable.thermal.control}
|
||||
|
||||
on property:persist.vendor.disable.thermalhal.control=*
|
||||
setprop vendor.disable.thermalhal.control ${persist.vendor.disable.thermalhal.control}
|
||||
|
||||
on property:persist.vendor.disable.usb.overheat.mitigation=*
|
||||
setprop vendor.disable.usb.overheat.mitigation.control ${persist.vendor.disable.usb.overheat.mitigation}
|
||||
|
||||
on property:persist.vendor.disable.bcl.control=*
|
||||
setprop vendor.disable.bcl.control ${persist.vendor.disable.bcl.control}
|
||||
|
||||
on property:vendor.disable.thermalhal.control=* && property:vendor.thermal.link_ready=1
|
||||
restart vendor.thermal-hal
|
||||
|
||||
on property:vendor.disable.thermal.control=1 && property:vendor.thermal.link_ready=1
|
||||
# common
|
||||
stop vendor.thermal-engine
|
||||
setprop vendor.disable.thermalhal.control 1
|
||||
# sdm845
|
||||
write /dev/thermal/tz-by-name/quiet-therm-adc/mode disabled
|
||||
write /dev/thermal/tz-by-name/quiet-therm-monitor/mode disabled
|
||||
write /dev/thermal/tz-by-name/fps-therm-adc/mode disabled
|
||||
write /dev/thermal/tz-by-name/fps-therm-monitor/mode disabled
|
||||
# sdm670
|
||||
write /dev/thermal/tz-by-name/mb-therm-adc/mode disabled
|
||||
write /dev/thermal/tz-by-name/mb-therm-monitor/mode disabled
|
||||
# sm8150
|
||||
write /dev/thermal/tz-by-name/sdm-therm/mode disabled
|
||||
write /dev/thermal/tz-by-name/sdm-therm-monitor/mode disabled
|
||||
# sm7150
|
||||
write /dev/thermal/tz-by-name/skin-therm-adc/mode disabled
|
||||
write /dev/thermal/tz-by-name/skin-therm-monitor/mode disabled
|
||||
# sm7250
|
||||
write /dev/thermal/tz-by-name/skin-therm/emul_temp 25000
|
||||
write /dev/thermal/tz-by-name/skin-therm/mode disabled
|
||||
write /dev/thermal/tz-by-name/skin-virt/emul_temp 25000
|
||||
write /dev/thermal/tz-by-name/skin-virt/mode disabled
|
||||
write /dev/thermal/tz-by-name/skin-therm-cpu/emul_temp 25000
|
||||
write /dev/thermal/tz-by-name/skin-therm-cpu/mode disabled
|
||||
write /dev/thermal/tz-by-name/skin-virt-cpu/emul_temp 25000
|
||||
write /dev/thermal/tz-by-name/skin-virt-cpu/mode disabled
|
||||
write /dev/thermal/tz-by-name/skin-therm-monitor/emul_temp 25000
|
||||
write /dev/thermal/tz-by-name/skin-therm-monitor/mode disabled
|
||||
write /dev/thermal/tz-by-name/skin-virt-monitor/emul_temp 25000
|
||||
write /dev/thermal/tz-by-name/skin-virt-monitor/mode disabled
|
||||
write /dev/thermal/tz-by-name/panel-audio-therm/emul_temp 25000
|
||||
write /dev/thermal/tz-by-name/panel-audio-therm/mode disabled
|
||||
write /dev/thermal/tz-by-name/cellular-emergency/emul_temp 25000
|
||||
write /dev/thermal/tz-by-name/cellular-emergency/mode disabled
|
||||
write /dev/thermal/tz-by-name/sdm-therm/emul_temp 25000
|
||||
write /dev/thermal/tz-by-name/sdm-therm/mode disabled
|
||||
write /dev/thermal/tz-by-name/charger-therm/emul_temp 25000
|
||||
write /dev/thermal/tz-by-name/charger-therm/mode disabled
|
||||
# P21
|
||||
write /dev/thermal/tz-by-name/disp_therm/mode disabled
|
||||
|
||||
on property:vendor.disable.thermal.control=0 && property:vendor.thermal.link_ready=1
|
||||
# common
|
||||
start vendor.thermal-engine
|
||||
setprop vendor.disable.thermalhal.control 0
|
||||
# sdm845
|
||||
write /dev/thermal/tz-by-name/quiet-therm-adc/mode enabled
|
||||
write /dev/thermal/tz-by-name/quiet-therm-monitor/mode enabled
|
||||
write /dev/thermal/tz-by-name/fps-therm-adc/mode enabled
|
||||
write /dev/thermal/tz-by-name/fps-therm-monitor/mode enabled
|
||||
# sdm670
|
||||
write /dev/thermal/tz-by-name/mb-therm-adc/mode enabled
|
||||
write /dev/thermal/tz-by-name/mb-therm-monitor/mode enabled
|
||||
# sm8150
|
||||
write /dev/thermal/tz-by-name/sdm-therm/mode enabled
|
||||
write /dev/thermal/tz-by-name/sdm-therm-monitor/mode enabled
|
||||
# sm7150
|
||||
write /dev/thermal/tz-by-name/skin-therm-adc/mode enabled
|
||||
write /dev/thermal/tz-by-name/skin-therm-monitor/mode enabled
|
||||
# sm7250
|
||||
write /dev/thermal/tz-by-name/skin-therm/emul_temp 0
|
||||
write /dev/thermal/tz-by-name/skin-therm/mode enabled
|
||||
write /dev/thermal/tz-by-name/skin-virt/emul_temp 0
|
||||
write /dev/thermal/tz-by-name/skin-virt/mode enabled
|
||||
write /dev/thermal/tz-by-name/skin-therm-cpu/emul_temp 0
|
||||
write /dev/thermal/tz-by-name/skin-therm-cpu/mode enabled
|
||||
write /dev/thermal/tz-by-name/skin-virt-cpu/emul_temp 0
|
||||
write /dev/thermal/tz-by-name/skin-virt-cpu/mode enabled
|
||||
write /dev/thermal/tz-by-name/skin-therm-monitor/emul_temp 0
|
||||
write /dev/thermal/tz-by-name/skin-therm-monitor/mode enabled
|
||||
write /dev/thermal/tz-by-name/skin-virt-monitor/emul_temp 0
|
||||
write /dev/thermal/tz-by-name/skin-virt-monitor/mode enabled
|
||||
write /dev/thermal/tz-by-name/panel-audio-therm/emul_temp 0
|
||||
write /dev/thermal/tz-by-name/panel-audio-therm/mode enabled
|
||||
write /dev/thermal/tz-by-name/cellular-emergency/emul_temp 0
|
||||
write /dev/thermal/tz-by-name/cellular-emergency/mode enabled
|
||||
write /dev/thermal/tz-by-name/sdm-therm/emul_temp 0
|
||||
write /dev/thermal/tz-by-name/sdm-therm/mode enabled
|
||||
write /dev/thermal/tz-by-name/charger-therm/emul_temp 0
|
||||
write /dev/thermal/tz-by-name/charger-therm/mode enabled
|
||||
# P21
|
||||
write /dev/thermal/tz-by-name/disp_therm/mode enabled
|
||||
|
||||
# Toggle BCL control
|
||||
on property:vendor.disable.bcl.control=1
|
||||
write /dev/thermal/tz-by-name/soc/mode disabled
|
||||
|
||||
on property:vendor.disable.bcl.control=0
|
||||
write /dev/thermal/tz-by-name/soc/mode enabled
|
||||
|
||||
# Switch USB port overheat protection
|
||||
on property:vendor.disable.usb.overheat.mitigation.control=1
|
||||
write /sys/module/overheat_mitigation/parameters/enable 0
|
||||
write /dev/thermal/tz-by-name/usb_pwr_therm2/emul_temp 25000
|
||||
|
||||
on property:vendor.disable.usb.overheat.mitigation.control=0
|
||||
write /sys/module/overheat_mitigation/parameters/enable 1
|
||||
write /dev/thermal/tz-by-name/usb_pwr_therm2/emul_temp 0
|
||||
@@ -1,11 +0,0 @@
|
||||
on boot
|
||||
mkdir /dev/thermal 0750 system system
|
||||
mkdir /dev/thermal/tz-by-name 0750 system system
|
||||
mkdir /dev/thermal/cdev-by-name 0750 system system
|
||||
start vendor.thermal.symlinks
|
||||
|
||||
service vendor.thermal.symlinks /vendor/bin/thermal_symlinks.samsung
|
||||
user system
|
||||
group system
|
||||
oneshot
|
||||
disabled
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
#include <android-base/logging.h>
|
||||
#include <android/binder_manager.h>
|
||||
#include <android/binder_process.h>
|
||||
|
||||
#include "Thermal.h"
|
||||
|
||||
constexpr std::string_view kThermalLogTag("samsung-thermal");
|
||||
|
||||
using ::android::OK;
|
||||
using ::android::status_t;
|
||||
|
||||
// Generated AIDL files:
|
||||
using Thermal = ::aidl::android::hardware::thermal::implementation::Thermal;
|
||||
|
||||
#if !defined(THERMAL_INSTANCE_NAME)
|
||||
#define THERMAL_INSTANCE_NAME "default"
|
||||
#endif
|
||||
|
||||
int main(int /* argc */, char ** /* argv */) {
|
||||
android::base::SetDefaultTag(kThermalLogTag.data());
|
||||
|
||||
auto svc = ndk::SharedRefBase::make<Thermal>();
|
||||
const auto svcName = std::string() + svc->descriptor + "/" + THERMAL_INSTANCE_NAME;
|
||||
LOG(INFO) << "Samsung Thermal AIDL Service starting..." + svcName;
|
||||
ABinderProcess_setThreadPoolMaxThreadCount(0);
|
||||
|
||||
auto svcBinder = svc->asBinder();
|
||||
binder_status_t status = AServiceManager_addService(svcBinder.get(), svcName.c_str());
|
||||
if (status != STATUS_OK) {
|
||||
LOG(ERROR) << "Samsung Thermal AIDL Service failed to start: " << status << ".";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
LOG(INFO) << "Samsung Thermal HAL AIDL Service started.";
|
||||
ABinderProcess_joinThreadPool();
|
||||
return EXIT_FAILURE; // should not reach
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,184 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <aidl/android/hardware/thermal/IThermal.h>
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "utils/power_files.h"
|
||||
#include "utils/powerhal_helper.h"
|
||||
#include "utils/thermal_files.h"
|
||||
#include "utils/thermal_info.h"
|
||||
#include "utils/thermal_throttling.h"
|
||||
#include "utils/thermal_watcher.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace thermal {
|
||||
namespace implementation {
|
||||
|
||||
using ::android::sp;
|
||||
|
||||
using NotificationCallback = std::function<void(const Temperature &t)>;
|
||||
|
||||
// Get thermal_zone type
|
||||
bool getThermalZoneTypeById(int tz_id, std::string *);
|
||||
|
||||
struct ThermalSample {
|
||||
float temp;
|
||||
boot_clock::time_point timestamp;
|
||||
};
|
||||
|
||||
struct EmulSetting {
|
||||
float emul_temp;
|
||||
int emul_severity;
|
||||
bool pending_update;
|
||||
};
|
||||
|
||||
struct SensorStatus {
|
||||
ThrottlingSeverity severity;
|
||||
ThrottlingSeverity prev_hot_severity;
|
||||
ThrottlingSeverity prev_cold_severity;
|
||||
ThrottlingSeverity prev_hint_severity;
|
||||
boot_clock::time_point last_update_time;
|
||||
ThermalSample thermal_cached;
|
||||
std::unique_ptr<EmulSetting> emul_setting;
|
||||
};
|
||||
|
||||
class ThermalHelper {
|
||||
public:
|
||||
explicit ThermalHelper(const NotificationCallback &cb);
|
||||
~ThermalHelper() = default;
|
||||
|
||||
bool fillCurrentTemperatures(bool filterType, bool filterCallback, TemperatureType type,
|
||||
std::vector<Temperature> *temperatures);
|
||||
bool fillTemperatureThresholds(bool filterType, TemperatureType type,
|
||||
std::vector<TemperatureThreshold> *thresholds) const;
|
||||
bool fillCurrentCoolingDevices(bool filterType, CoolingType type,
|
||||
std::vector<CoolingDevice> *coolingdevices) const;
|
||||
bool emulTemp(std::string_view target_sensor, const float temp);
|
||||
bool emulSeverity(std::string_view target_sensor, const int severity);
|
||||
bool emulClear(std::string_view target_sensor);
|
||||
|
||||
// Disallow copy and assign.
|
||||
ThermalHelper(const ThermalHelper &) = delete;
|
||||
void operator=(const ThermalHelper &) = delete;
|
||||
|
||||
bool isInitializedOk() const { return is_initialized_; }
|
||||
|
||||
// Read the temperature of a single sensor.
|
||||
bool readTemperature(std::string_view sensor_name, Temperature *out);
|
||||
bool readTemperature(
|
||||
std::string_view sensor_name, Temperature *out,
|
||||
std::pair<ThrottlingSeverity, ThrottlingSeverity> *throtting_status = nullptr,
|
||||
const bool force_sysfs = false);
|
||||
|
||||
bool readTemperatureThreshold(std::string_view sensor_name, TemperatureThreshold *out) const;
|
||||
// Read the value of a single cooling device.
|
||||
bool readCoolingDevice(std::string_view cooling_device, CoolingDevice *out) const;
|
||||
// Get SensorInfo Map
|
||||
const std::unordered_map<std::string, SensorInfo> &GetSensorInfoMap() const {
|
||||
return sensor_info_map_;
|
||||
}
|
||||
// Get CdevInfo Map
|
||||
const std::unordered_map<std::string, CdevInfo> &GetCdevInfoMap() const {
|
||||
return cooling_device_info_map_;
|
||||
}
|
||||
// Get SensorStatus Map
|
||||
const std::unordered_map<std::string, SensorStatus> &GetSensorStatusMap() const {
|
||||
std::shared_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
|
||||
return sensor_status_map_;
|
||||
}
|
||||
// Get ThermalThrottling Map
|
||||
const std::unordered_map<std::string, ThermalThrottlingStatus> &GetThermalThrottlingStatusMap()
|
||||
const {
|
||||
return thermal_throttling_.GetThermalThrottlingStatusMap();
|
||||
}
|
||||
// Get PowerRailInfo Map
|
||||
const std::unordered_map<std::string, PowerRailInfo> &GetPowerRailInfoMap() const {
|
||||
return power_files_.GetPowerRailInfoMap();
|
||||
}
|
||||
|
||||
// Get PowerStatus Map
|
||||
const std::unordered_map<std::string, PowerStatus> &GetPowerStatusMap() const {
|
||||
return power_files_.GetPowerStatusMap();
|
||||
}
|
||||
|
||||
void sendPowerExtHint(const Temperature &t);
|
||||
bool isAidlPowerHalExist() { return power_hal_service_.isAidlPowerHalExist(); }
|
||||
bool isPowerHalConnected() { return power_hal_service_.isPowerHalConnected(); }
|
||||
bool isPowerHalExtConnected() { return power_hal_service_.isPowerHalExtConnected(); }
|
||||
|
||||
private:
|
||||
bool initializeSensorMap(const std::unordered_map<std::string, std::string> &path_map);
|
||||
bool initializeCoolingDevices(const std::unordered_map<std::string, std::string> &path_map);
|
||||
bool isSubSensorValid(std::string_view sensor_data, const SensorFusionType sensor_fusion_type);
|
||||
void setMinTimeout(SensorInfo *sensor_info);
|
||||
void initializeTrip(const std::unordered_map<std::string, std::string> &path_map,
|
||||
std::set<std::string> *monitored_sensors, bool thermal_genl_enabled);
|
||||
void clearAllThrottling();
|
||||
// For thermal_watcher_'s polling thread, return the sleep interval
|
||||
std::chrono::milliseconds thermalWatcherCallbackFunc(
|
||||
const std::set<std::string> &uevent_sensors);
|
||||
// Return hot and cold severity status as std::pair
|
||||
std::pair<ThrottlingSeverity, ThrottlingSeverity> getSeverityFromThresholds(
|
||||
const ThrottlingArray &hot_thresholds, const ThrottlingArray &cold_thresholds,
|
||||
const ThrottlingArray &hot_hysteresis, const ThrottlingArray &cold_hysteresis,
|
||||
ThrottlingSeverity prev_hot_severity, ThrottlingSeverity prev_cold_severity,
|
||||
float value) const;
|
||||
// Read sensor data according to the type
|
||||
bool readDataByType(std::string_view sensor_data, float *reading_value,
|
||||
const SensorFusionType type, const bool force_no_cache,
|
||||
std::map<std::string, float> *sensor_log_map);
|
||||
// Read temperature data according to thermal sensor's info
|
||||
bool readThermalSensor(std::string_view sensor_name, float *temp, const bool force_sysfs,
|
||||
std::map<std::string, float> *sensor_log_map);
|
||||
bool connectToPowerHal();
|
||||
void updateSupportedPowerHints();
|
||||
void updateCoolingDevices(const std::vector<std::string> &cooling_devices_to_update);
|
||||
sp<ThermalWatcher> thermal_watcher_;
|
||||
PowerFiles power_files_;
|
||||
ThermalFiles thermal_sensors_;
|
||||
ThermalFiles cooling_devices_;
|
||||
ThermalThrottling thermal_throttling_;
|
||||
bool is_initialized_;
|
||||
const NotificationCallback cb_;
|
||||
std::unordered_map<std::string, CdevInfo> cooling_device_info_map_;
|
||||
std::unordered_map<std::string, SensorInfo> sensor_info_map_;
|
||||
std::unordered_map<std::string, std::unordered_map<ThrottlingSeverity, ThrottlingSeverity>>
|
||||
supported_powerhint_map_;
|
||||
PowerHalService power_hal_service_;
|
||||
mutable std::shared_mutex sensor_status_map_mutex_;
|
||||
std::unordered_map<std::string, SensorStatus> sensor_status_map_;
|
||||
};
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace thermal
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -1,219 +0,0 @@
|
||||
{
|
||||
"definitions":{
|
||||
|
||||
},
|
||||
"$schema":"http://json-schema.org/draft-07/schema#",
|
||||
"$id":"http://example.com/root.json",
|
||||
"type":"object",
|
||||
"title":"The Root Schema",
|
||||
"required":[
|
||||
"Sensors"
|
||||
],
|
||||
"properties":{
|
||||
"Sensors":{
|
||||
"$id":"#/properties/Sensors",
|
||||
"type":"array",
|
||||
"title":"The Sensors Schema",
|
||||
"items":{
|
||||
"$id":"#/properties/Sensors/items",
|
||||
"type":"object",
|
||||
"title":"The Items Schema",
|
||||
"required":[
|
||||
"Name",
|
||||
"Type",
|
||||
"HotThreshold",
|
||||
"VrThreshold",
|
||||
"Multiplier"
|
||||
],
|
||||
"properties":{
|
||||
"Name":{
|
||||
"$id":"#/properties/Sensors/items/properties/Name",
|
||||
"type":"string",
|
||||
"title":"The Name Schema",
|
||||
"default":"",
|
||||
"examples":[
|
||||
"cpu0-silver-usr"
|
||||
],
|
||||
"pattern":"^(.+)$"
|
||||
},
|
||||
"Type":{
|
||||
"$id":"#/properties/Sensors/items/properties/Type",
|
||||
"type":"string",
|
||||
"title":"The Type Schema",
|
||||
"default":"",
|
||||
"examples":[
|
||||
"CPU"
|
||||
],
|
||||
"pattern":"^(.+)$"
|
||||
},
|
||||
"HotThreshold":{
|
||||
"$id":"#/properties/Sensors/items/properties/HotThreshold",
|
||||
"type":"array",
|
||||
"title":"The hot threshold Schema, values are thresholds from ThrottlingSeverity::NONE to ThrottlingSeverity::SHUTDOWN",
|
||||
"default":"NAN",
|
||||
"maxItems":7,
|
||||
"minItems":7,
|
||||
"items":{
|
||||
"$id":"#/properties/Sensors/items/properties/HotThreshold/items",
|
||||
"type":[
|
||||
"string",
|
||||
"number"
|
||||
],
|
||||
"title":"The Items Schema",
|
||||
"default":"",
|
||||
"examples":[
|
||||
"NAN",
|
||||
"NAN",
|
||||
"NAN",
|
||||
95,
|
||||
"NAN",
|
||||
"NAN",
|
||||
125
|
||||
],
|
||||
"pattern":"^([-+]?[0-9]*\\.?[0-9]+|NAN)$"
|
||||
}
|
||||
},
|
||||
"HotHysteresis":{
|
||||
"$id":"#/properties/Sensors/items/properties/HotHysteresis",
|
||||
"type":"array",
|
||||
"title":"The hot hysteresis Schema, values are thresholds from ThrottlingSeverity::NONE to ThrottlingSeverity::SHUTDOWN. Throttling status will be cleared HotThreshold - HotHysteresis.",
|
||||
"default":null,
|
||||
"maxItems":7,
|
||||
"minItems":7,
|
||||
"items":{
|
||||
"$id":"#/properties/Sensors/items/properties/HotHysteresis/items",
|
||||
"type":[
|
||||
"number"
|
||||
],
|
||||
"title":"The Items Schema",
|
||||
"default":0.0,
|
||||
"examples":[
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0,
|
||||
1.5,
|
||||
1.0,
|
||||
2.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"ColdThreshold":{
|
||||
"$id":"#/properties/Sensors/items/properties/ColdThreshold",
|
||||
"type":"array",
|
||||
"title":"The cold threshold Schema, values are thresholds from ThrottlingSeverity::NONE to ThrottlingSeverity::SHUTDOWN, default to NAN",
|
||||
"default":null,
|
||||
"maxItems":7,
|
||||
"minItems":7,
|
||||
"items":{
|
||||
"$id":"#/properties/Sensors/items/properties/ColdThreshold/items",
|
||||
"type":"string",
|
||||
"title":"The Items Schema",
|
||||
"default":"NAN",
|
||||
"examples":[
|
||||
"NAN",
|
||||
"NAN",
|
||||
"NAN",
|
||||
"NAN",
|
||||
"NAN",
|
||||
"NAN",
|
||||
"NAN"
|
||||
],
|
||||
"pattern":"^([-+]?[0-9]*\\.?[0-9]+|NAN)$"
|
||||
}
|
||||
},
|
||||
"ColdHysteresis":{
|
||||
"$id":"#/properties/Sensors/items/properties/ColdHysteresis",
|
||||
"type":"array",
|
||||
"title":"The cold hysteresis Schema, values are thresholds from ThrottlingSeverity::NONE to ThrottlingSeverity::SHUTDOWN. Throttling status will be cleared ColdThreshold + ColdHysteresis.",
|
||||
"default":null,
|
||||
"maxItems":7,
|
||||
"minItems":7,
|
||||
"items":{
|
||||
"$id":"#/properties/Sensors/items/properties/ColdHysteresis/items",
|
||||
"type":[
|
||||
"number"
|
||||
],
|
||||
"title":"The Items Schema",
|
||||
"default":0.0,
|
||||
"examples":[
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0,
|
||||
1.5,
|
||||
1.0,
|
||||
2.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"VrThreshold":{
|
||||
"$id":"#/properties/Sensors/items/properties/VrThreshold",
|
||||
"type":"string",
|
||||
"title":"The Vrthreshold Schema",
|
||||
"default":"",
|
||||
"examples":[
|
||||
"NAN"
|
||||
],
|
||||
"pattern":"^(.*)$"
|
||||
},
|
||||
"Multiplier":{
|
||||
"$id":"#/properties/Sensors/items/properties/Multiplier",
|
||||
"type":"number",
|
||||
"title":"The Multiplier Schema",
|
||||
"default":0.001,
|
||||
"examples":[
|
||||
0.001
|
||||
],
|
||||
"exclusiveMinimum":0.0
|
||||
},
|
||||
"Monitor":{
|
||||
"$id":"#/properties/Sensors/items/properties/Monitor",
|
||||
"type":"boolean",
|
||||
"title":"The Monitor Schema, if the sensor will be monitored and used to trigger throttling event",
|
||||
"default":false,
|
||||
"examples":[
|
||||
true
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"CoolingDevices":{
|
||||
"$id":"#/properties/CoolingDevices",
|
||||
"type":"array",
|
||||
"title":"The Coolingdevices Schema",
|
||||
"items":{
|
||||
"$id":"#/properties/CoolingDevices/items",
|
||||
"type":"object",
|
||||
"title":"The Items Schema",
|
||||
"required":[
|
||||
"Name",
|
||||
"Type"
|
||||
],
|
||||
"properties":{
|
||||
"Name":{
|
||||
"$id":"#/properties/CoolingDevices/items/properties/Name",
|
||||
"type":"string",
|
||||
"title":"The Name Schema",
|
||||
"default":"",
|
||||
"examples":[
|
||||
"thermal-cpufreq-0"
|
||||
],
|
||||
"pattern":"^(.+)$"
|
||||
},
|
||||
"Type":{
|
||||
"$id":"#/properties/CoolingDevices/items/properties/Type",
|
||||
"type":"string",
|
||||
"title":"The Type Schema",
|
||||
"default":"",
|
||||
"examples":[
|
||||
"CPU"
|
||||
],
|
||||
"pattern":"^(.+)$"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,342 +0,0 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 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_THERMAL | ATRACE_TAG_HAL)
|
||||
|
||||
#include "power_files.h"
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <dirent.h>
|
||||
#include <utils/Trace.h>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace thermal {
|
||||
namespace implementation {
|
||||
|
||||
constexpr std::string_view kDeviceType("iio:device");
|
||||
constexpr std::string_view kIioRootDir("/sys/bus/iio/devices");
|
||||
constexpr std::string_view kEnergyValueNode("energy_value");
|
||||
|
||||
using ::android::base::ReadFileToString;
|
||||
using ::android::base::StringPrintf;
|
||||
|
||||
bool PowerFiles::registerPowerRailsToWatch(const Json::Value &config) {
|
||||
if (!ParsePowerRailInfo(config, &power_rail_info_map_)) {
|
||||
LOG(ERROR) << "Failed to parse power rail info config";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!power_rail_info_map_.size()) {
|
||||
LOG(INFO) << " No power rail info config found";
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!findEnergySourceToWatch()) {
|
||||
LOG(ERROR) << "Cannot find energy source";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!energy_info_map_.size() && !updateEnergyValues()) {
|
||||
LOG(ERROR) << "Faield to update energy info";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto &power_rail_info_pair : power_rail_info_map_) {
|
||||
std::vector<std::queue<PowerSample>> power_history;
|
||||
if (!power_rail_info_pair.second.power_sample_count ||
|
||||
power_rail_info_pair.second.power_sample_delay == std::chrono::milliseconds::max()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PowerSample power_sample = {
|
||||
.energy_counter = 0,
|
||||
.duration = 0,
|
||||
};
|
||||
|
||||
if (power_rail_info_pair.second.virtual_power_rail_info != nullptr &&
|
||||
power_rail_info_pair.second.virtual_power_rail_info->linked_power_rails.size()) {
|
||||
for (size_t i = 0;
|
||||
i < power_rail_info_pair.second.virtual_power_rail_info->linked_power_rails.size();
|
||||
++i) {
|
||||
if (!energy_info_map_.count(power_rail_info_pair.second.virtual_power_rail_info
|
||||
->linked_power_rails[i])) {
|
||||
LOG(ERROR) << " Could not find energy source "
|
||||
<< power_rail_info_pair.second.virtual_power_rail_info
|
||||
->linked_power_rails[i];
|
||||
return false;
|
||||
}
|
||||
power_history.emplace_back(std::queue<PowerSample>());
|
||||
for (int j = 0; j < power_rail_info_pair.second.power_sample_count; j++) {
|
||||
power_history[i].emplace(power_sample);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (energy_info_map_.count(power_rail_info_pair.first)) {
|
||||
power_history.emplace_back(std::queue<PowerSample>());
|
||||
for (int j = 0; j < power_rail_info_pair.second.power_sample_count; j++) {
|
||||
power_history[0].emplace(power_sample);
|
||||
}
|
||||
} else {
|
||||
LOG(ERROR) << "Could not find energy source " << power_rail_info_pair.first;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (power_history.size()) {
|
||||
power_status_map_[power_rail_info_pair.first] = {
|
||||
.power_history = power_history,
|
||||
.last_update_time = boot_clock::time_point::min(),
|
||||
.last_updated_avg_power = NAN,
|
||||
};
|
||||
} else {
|
||||
LOG(ERROR) << "power history size is zero";
|
||||
return false;
|
||||
}
|
||||
LOG(INFO) << "Successfully to register power rail " << power_rail_info_pair.first;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PowerFiles::findEnergySourceToWatch(void) {
|
||||
std::string devicePath;
|
||||
|
||||
if (energy_path_set_.size()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(kIioRootDir.data()), closedir);
|
||||
if (!dir) {
|
||||
PLOG(ERROR) << "Error opening directory" << kIioRootDir;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find any iio:devices that support energy_value
|
||||
while (struct dirent *ent = readdir(dir.get())) {
|
||||
std::string devTypeDir = ent->d_name;
|
||||
if (devTypeDir.find(kDeviceType) != std::string::npos) {
|
||||
devicePath = StringPrintf("%s/%s", kIioRootDir.data(), devTypeDir.data());
|
||||
std::string deviceEnergyContent;
|
||||
|
||||
if (!ReadFileToString(StringPrintf("%s/%s", devicePath.data(), kEnergyValueNode.data()),
|
||||
&deviceEnergyContent)) {
|
||||
} else if (deviceEnergyContent.size()) {
|
||||
energy_path_set_.emplace(
|
||||
StringPrintf("%s/%s", devicePath.data(), kEnergyValueNode.data()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!energy_path_set_.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PowerFiles::updateEnergyValues(void) {
|
||||
std::string deviceEnergyContent;
|
||||
std::string deviceEnergyContents;
|
||||
std::string line;
|
||||
|
||||
ATRACE_CALL();
|
||||
for (const auto &path : energy_path_set_) {
|
||||
if (!::android::base::ReadFileToString(path, &deviceEnergyContent)) {
|
||||
LOG(ERROR) << "Failed to read energy content from " << path;
|
||||
return false;
|
||||
} else {
|
||||
deviceEnergyContents.append(deviceEnergyContent);
|
||||
}
|
||||
}
|
||||
|
||||
std::istringstream energyData(deviceEnergyContents);
|
||||
|
||||
while (std::getline(energyData, line)) {
|
||||
/* Read rail energy */
|
||||
uint64_t energy_counter = 0;
|
||||
uint64_t duration = 0;
|
||||
|
||||
/* Format example: CH3(T=358356)[S2M_VDD_CPUCL2], 761330 */
|
||||
auto start_pos = line.find("T=");
|
||||
auto end_pos = line.find(')');
|
||||
if (start_pos != std::string::npos) {
|
||||
duration =
|
||||
strtoul(line.substr(start_pos + 2, end_pos - start_pos - 2).c_str(), NULL, 10);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
start_pos = line.find(")[");
|
||||
end_pos = line.find(']');
|
||||
std::string railName;
|
||||
if (start_pos != std::string::npos) {
|
||||
railName = line.substr(start_pos + 2, end_pos - start_pos - 2);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
start_pos = line.find("],");
|
||||
if (start_pos != std::string::npos) {
|
||||
energy_counter = strtoul(line.substr(start_pos + 2).c_str(), NULL, 10);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
energy_info_map_[railName] = {
|
||||
.energy_counter = energy_counter,
|
||||
.duration = duration,
|
||||
};
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float PowerFiles::updateAveragePower(std::string_view power_rail,
|
||||
std::queue<PowerSample> *power_history) {
|
||||
float avg_power = NAN;
|
||||
|
||||
if (!energy_info_map_.count(power_rail.data())) {
|
||||
LOG(ERROR) << " Could not find power rail " << power_rail.data();
|
||||
return avg_power;
|
||||
}
|
||||
const auto last_sample = power_history->front();
|
||||
const auto curr_sample = energy_info_map_.at(power_rail.data());
|
||||
const auto duration = curr_sample.duration - last_sample.duration;
|
||||
const auto deltaEnergy = curr_sample.energy_counter - last_sample.energy_counter;
|
||||
|
||||
if (!last_sample.duration) {
|
||||
LOG(VERBOSE) << "Power rail " << power_rail.data()
|
||||
<< ": all power samples have not been collected yet";
|
||||
} else if (duration <= 0 || deltaEnergy < 0) {
|
||||
LOG(ERROR) << "Power rail " << power_rail.data() << " is invalid: duration = " << duration
|
||||
<< ", deltaEnergy = " << deltaEnergy;
|
||||
|
||||
return avg_power;
|
||||
} else {
|
||||
avg_power = static_cast<float>(deltaEnergy) / static_cast<float>(duration);
|
||||
LOG(VERBOSE) << "Power rail " << power_rail.data() << ", avg power = " << avg_power
|
||||
<< ", duration = " << duration << ", deltaEnergy = " << deltaEnergy;
|
||||
}
|
||||
|
||||
power_history->pop();
|
||||
power_history->push(curr_sample);
|
||||
|
||||
return avg_power;
|
||||
}
|
||||
|
||||
float PowerFiles::updatePowerRail(std::string_view power_rail) {
|
||||
float avg_power = NAN;
|
||||
|
||||
if (!power_rail_info_map_.count(power_rail.data())) {
|
||||
return avg_power;
|
||||
}
|
||||
|
||||
if (!power_status_map_.count(power_rail.data())) {
|
||||
return avg_power;
|
||||
}
|
||||
|
||||
const auto &power_rail_info = power_rail_info_map_.at(power_rail.data());
|
||||
auto &power_status = power_status_map_.at(power_rail.data());
|
||||
|
||||
boot_clock::time_point now = boot_clock::now();
|
||||
auto time_elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
now - power_status.last_update_time);
|
||||
|
||||
if (power_status.last_update_time != boot_clock::time_point::min() &&
|
||||
time_elapsed_ms < power_rail_info.power_sample_delay) {
|
||||
return power_status.last_updated_avg_power;
|
||||
}
|
||||
|
||||
if (!energy_info_map_.size() && !updateEnergyValues()) {
|
||||
LOG(ERROR) << "Failed to update energy values";
|
||||
return avg_power;
|
||||
}
|
||||
|
||||
if (power_rail_info.virtual_power_rail_info == nullptr) {
|
||||
avg_power = updateAveragePower(power_rail, &power_status.power_history[0]);
|
||||
} else {
|
||||
const auto offset = power_rail_info.virtual_power_rail_info->offset;
|
||||
float avg_power_val = 0.0;
|
||||
for (size_t i = 0; i < power_rail_info.virtual_power_rail_info->linked_power_rails.size();
|
||||
i++) {
|
||||
float coefficient = power_rail_info.virtual_power_rail_info->coefficients[i];
|
||||
float avg_power_number = updateAveragePower(
|
||||
power_rail_info.virtual_power_rail_info->linked_power_rails[i],
|
||||
&power_status.power_history[i]);
|
||||
|
||||
switch (power_rail_info.virtual_power_rail_info->formula) {
|
||||
case FormulaOption::COUNT_THRESHOLD:
|
||||
if ((coefficient < 0 && avg_power_number < -coefficient) ||
|
||||
(coefficient >= 0 && avg_power_number >= coefficient))
|
||||
avg_power_val += 1;
|
||||
break;
|
||||
case FormulaOption::WEIGHTED_AVG:
|
||||
avg_power_val += avg_power_number * coefficient;
|
||||
break;
|
||||
case FormulaOption::MAXIMUM:
|
||||
if (i == 0)
|
||||
avg_power_val = std::numeric_limits<float>::lowest();
|
||||
if (avg_power_number * coefficient > avg_power_val)
|
||||
avg_power_val = avg_power_number * coefficient;
|
||||
break;
|
||||
case FormulaOption::MINIMUM:
|
||||
if (i == 0)
|
||||
avg_power_val = std::numeric_limits<float>::max();
|
||||
if (avg_power_number * coefficient < avg_power_val)
|
||||
avg_power_val = avg_power_number * coefficient;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (avg_power_val >= 0) {
|
||||
avg_power_val = avg_power_val + offset;
|
||||
}
|
||||
|
||||
avg_power = avg_power_val;
|
||||
}
|
||||
|
||||
if (avg_power < 0) {
|
||||
avg_power = NAN;
|
||||
}
|
||||
|
||||
power_status.last_updated_avg_power = avg_power;
|
||||
power_status.last_update_time = now;
|
||||
return avg_power;
|
||||
}
|
||||
|
||||
bool PowerFiles::refreshPowerStatus(void) {
|
||||
if (!updateEnergyValues()) {
|
||||
LOG(ERROR) << "Failed to update energy values";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto &power_status_pair : power_status_map_) {
|
||||
updatePowerRail(power_status_pair.first);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace thermal
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <android-base/chrono_utils.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <queue>
|
||||
#include <shared_mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "thermal_info.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace thermal {
|
||||
namespace implementation {
|
||||
|
||||
using ::android::base::boot_clock;
|
||||
|
||||
struct PowerSample {
|
||||
uint64_t energy_counter;
|
||||
uint64_t duration;
|
||||
};
|
||||
|
||||
struct PowerStatus {
|
||||
boot_clock::time_point last_update_time;
|
||||
// A vector to record the queues of power sample history.
|
||||
std::vector<std::queue<PowerSample>> power_history;
|
||||
float last_updated_avg_power;
|
||||
};
|
||||
|
||||
// A helper class for monitoring power rails.
|
||||
class PowerFiles {
|
||||
public:
|
||||
PowerFiles() = default;
|
||||
~PowerFiles() = default;
|
||||
// Disallow copy and assign.
|
||||
PowerFiles(const PowerFiles &) = delete;
|
||||
void operator=(const PowerFiles &) = delete;
|
||||
bool registerPowerRailsToWatch(const Json::Value &config);
|
||||
// Update the power data from ODPM sysfs
|
||||
bool refreshPowerStatus(void);
|
||||
// Get power status map
|
||||
const std::unordered_map<std::string, PowerStatus> &GetPowerStatusMap() const {
|
||||
std::shared_lock<std::shared_mutex> _lock(power_status_map_mutex_);
|
||||
return power_status_map_;
|
||||
}
|
||||
// Get power rail info map
|
||||
const std::unordered_map<std::string, PowerRailInfo> &GetPowerRailInfoMap() const {
|
||||
return power_rail_info_map_;
|
||||
}
|
||||
|
||||
private:
|
||||
// Update energy value to energy_info_map_, return false if the value is failed to update.
|
||||
bool updateEnergyValues(void);
|
||||
// Compute the average power for physical power rail.
|
||||
float updateAveragePower(std::string_view power_rail, std::queue<PowerSample> *power_history);
|
||||
// Update the power data for the target power rail.
|
||||
float updatePowerRail(std::string_view power_rail);
|
||||
// Find the energy source path, return false if no energy source found.
|
||||
bool findEnergySourceToWatch(void);
|
||||
// The map to record the energy counter for each power rail.
|
||||
std::unordered_map<std::string, PowerSample> energy_info_map_;
|
||||
// The map to record the power data for each thermal sensor.
|
||||
std::unordered_map<std::string, PowerStatus> power_status_map_;
|
||||
mutable std::shared_mutex power_status_map_mutex_;
|
||||
// The map to record the power rail information from thermal config
|
||||
std::unordered_map<std::string, PowerRailInfo> power_rail_info_map_;
|
||||
// The set to store the energy source paths
|
||||
std::unordered_set<std::string> energy_path_set_;
|
||||
};
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace thermal
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
#include "powerhal_helper.h"
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <android/binder_manager.h>
|
||||
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "thermal_info.h"
|
||||
#include "thermal_throttling.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace thermal {
|
||||
namespace implementation {
|
||||
|
||||
using ::android::base::StringPrintf;
|
||||
|
||||
PowerHalService::PowerHalService()
|
||||
: power_hal_aidl_exist_(true), power_hal_aidl_(nullptr), power_hal_ext_aidl_(nullptr) {
|
||||
connect();
|
||||
}
|
||||
|
||||
bool PowerHalService::connect() {
|
||||
std::lock_guard<std::mutex> lock(lock_);
|
||||
|
||||
if (!power_hal_aidl_exist_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (power_hal_aidl_ && power_hal_ext_aidl_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::string kInstance = std::string(IPower::descriptor) + "/default";
|
||||
ndk::SpAIBinder power_binder = ndk::SpAIBinder(AServiceManager_getService(kInstance.c_str()));
|
||||
ndk::SpAIBinder ext_power_binder;
|
||||
|
||||
if (power_binder.get() == nullptr) {
|
||||
LOG(ERROR) << "Cannot get Power Hal Binder";
|
||||
power_hal_aidl_exist_ = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
power_hal_aidl_ = IPower::fromBinder(power_binder);
|
||||
|
||||
if (power_hal_aidl_ == nullptr) {
|
||||
power_hal_aidl_exist_ = false;
|
||||
LOG(ERROR) << "Cannot get Power Hal AIDL" << kInstance.c_str();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (STATUS_OK != AIBinder_getExtension(power_binder.get(), ext_power_binder.getR()) ||
|
||||
ext_power_binder.get() == nullptr) {
|
||||
LOG(ERROR) << "Cannot get Power Hal Extension Binder";
|
||||
power_hal_aidl_exist_ = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
power_hal_ext_aidl_ = IPowerExt::fromBinder(ext_power_binder);
|
||||
if (power_hal_ext_aidl_ == nullptr) {
|
||||
LOG(ERROR) << "Cannot get Power Hal Extension AIDL";
|
||||
power_hal_aidl_exist_ = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PowerHalService::isModeSupported(const std::string &type, const ThrottlingSeverity &t) {
|
||||
bool isSupported = false;
|
||||
if (!connect()) {
|
||||
return false;
|
||||
}
|
||||
std::string power_hint = StringPrintf("THERMAL_%s_%s", type.c_str(), toString(t).c_str());
|
||||
lock_.lock();
|
||||
if (!power_hal_ext_aidl_->isModeSupported(power_hint, &isSupported).isOk()) {
|
||||
LOG(ERROR) << "Fail to check supported mode, Hint: " << power_hint;
|
||||
power_hal_ext_aidl_ = nullptr;
|
||||
power_hal_aidl_ = nullptr;
|
||||
lock_.unlock();
|
||||
return false;
|
||||
}
|
||||
lock_.unlock();
|
||||
return isSupported;
|
||||
}
|
||||
|
||||
void PowerHalService::setMode(const std::string &type, const ThrottlingSeverity &t,
|
||||
const bool &enable, const bool error_on_exit) {
|
||||
if (!connect()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string power_hint = StringPrintf("THERMAL_%s_%s", type.c_str(), toString(t).c_str());
|
||||
LOG(INFO) << (error_on_exit ? "Resend Hint " : "Send Hint ") << power_hint
|
||||
<< " Enable: " << std::boolalpha << enable;
|
||||
lock_.lock();
|
||||
if (!power_hal_ext_aidl_->setMode(power_hint, enable).isOk()) {
|
||||
LOG(ERROR) << "Fail to set mode, Hint: " << power_hint;
|
||||
power_hal_ext_aidl_ = nullptr;
|
||||
power_hal_aidl_ = nullptr;
|
||||
lock_.unlock();
|
||||
if (!error_on_exit) {
|
||||
setMode(type, t, enable, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
lock_.unlock();
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace thermal
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <aidl/android/hardware/power/IPower.h>
|
||||
#include <aidl/android/hardware/thermal/ThrottlingSeverity.h>
|
||||
#include <aidl/google/hardware/power/extension/pixel/IPowerExt.h>
|
||||
|
||||
#include <queue>
|
||||
#include <shared_mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace thermal {
|
||||
namespace implementation {
|
||||
|
||||
using ::aidl::android::hardware::power::IPower;
|
||||
using ::aidl::google::hardware::power::extension::pixel::IPowerExt;
|
||||
|
||||
using CdevRequestStatus = std::unordered_map<std::string, int>;
|
||||
|
||||
class PowerHalService {
|
||||
public:
|
||||
PowerHalService();
|
||||
~PowerHalService() = default;
|
||||
bool connect();
|
||||
bool isAidlPowerHalExist() { return power_hal_aidl_exist_; }
|
||||
bool isModeSupported(const std::string &type, const ThrottlingSeverity &t);
|
||||
bool isPowerHalConnected() { return power_hal_aidl_ != nullptr; }
|
||||
bool isPowerHalExtConnected() { return power_hal_ext_aidl_ != nullptr; }
|
||||
void setMode(const std::string &type, const ThrottlingSeverity &t, const bool &enable,
|
||||
const bool error_on_exit = false);
|
||||
|
||||
private:
|
||||
bool power_hal_aidl_exist_;
|
||||
std::shared_ptr<IPower> power_hal_aidl_;
|
||||
std::shared_ptr<IPowerExt> power_hal_ext_aidl_;
|
||||
std::mutex lock_;
|
||||
};
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace thermal
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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_THERMAL | ATRACE_TAG_HAL)
|
||||
|
||||
#include "thermal_files.h"
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <utils/Trace.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string_view>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace thermal {
|
||||
namespace implementation {
|
||||
|
||||
using ::android::base::StringPrintf;
|
||||
|
||||
std::string ThermalFiles::getThermalFilePath(std::string_view thermal_name) const {
|
||||
auto sensor_itr = thermal_name_to_path_map_.find(thermal_name.data());
|
||||
if (sensor_itr == thermal_name_to_path_map_.end()) {
|
||||
return "";
|
||||
}
|
||||
return sensor_itr->second;
|
||||
}
|
||||
|
||||
bool ThermalFiles::addThermalFile(std::string_view thermal_name, std::string_view path) {
|
||||
return thermal_name_to_path_map_.emplace(thermal_name, path).second;
|
||||
}
|
||||
|
||||
bool ThermalFiles::readThermalFile(std::string_view thermal_name, std::string *data) const {
|
||||
std::string sensor_reading;
|
||||
std::string file_path = getThermalFilePath(std::string_view(thermal_name));
|
||||
*data = "";
|
||||
|
||||
ATRACE_NAME(StringPrintf("ThermalFiles::readThermalFile - %s", thermal_name.data()).c_str());
|
||||
if (file_path.empty()) {
|
||||
PLOG(WARNING) << "Failed to find " << thermal_name << "'s path";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!::android::base::ReadFileToString(file_path, &sensor_reading)) {
|
||||
PLOG(WARNING) << "Failed to read sensor: " << thermal_name;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Strip the newline.
|
||||
*data = ::android::base::Trim(sensor_reading);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThermalFiles::writeCdevFile(std::string_view cdev_name, std::string_view data) {
|
||||
std::string file_path =
|
||||
getThermalFilePath(::android::base::StringPrintf("%s_%s", cdev_name.data(), "w"));
|
||||
|
||||
ATRACE_NAME(StringPrintf("ThermalFiles::writeCdevFile - %s", cdev_name.data()).c_str());
|
||||
if (!::android::base::WriteStringToFile(data.data(), file_path)) {
|
||||
PLOG(WARNING) << "Failed to write cdev: " << cdev_name << " to " << data.data();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace thermal
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace thermal {
|
||||
namespace implementation {
|
||||
|
||||
class ThermalFiles {
|
||||
public:
|
||||
ThermalFiles() = default;
|
||||
~ThermalFiles() = default;
|
||||
ThermalFiles(const ThermalFiles &) = delete;
|
||||
void operator=(const ThermalFiles &) = delete;
|
||||
|
||||
std::string getThermalFilePath(std::string_view thermal_name) const;
|
||||
// Returns true if add was successful, false otherwise.
|
||||
bool addThermalFile(std::string_view thermal_name, std::string_view path);
|
||||
// If thermal_name is not found in the thermal names to path map, this will set
|
||||
// data to empty and return false. If the thermal_name is found and its content
|
||||
// is read, this function will fill in data accordingly then return true.
|
||||
bool readThermalFile(std::string_view thermal_name, std::string *data) const;
|
||||
bool writeCdevFile(std::string_view thermal_name, std::string_view data);
|
||||
size_t getNumThermalFiles() const { return thermal_name_to_path_map_.size(); }
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, std::string> thermal_name_to_path_map_;
|
||||
};
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace thermal
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,205 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <aidl/android/hardware/thermal/CoolingType.h>
|
||||
#include <aidl/android/hardware/thermal/TemperatureType.h>
|
||||
#include <aidl/android/hardware/thermal/ThrottlingSeverity.h>
|
||||
#include <json/value.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <variant>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace thermal {
|
||||
namespace implementation {
|
||||
|
||||
constexpr size_t kThrottlingSeverityCount =
|
||||
std::distance(::ndk::enum_range<ThrottlingSeverity>().begin(),
|
||||
::ndk::enum_range<ThrottlingSeverity>().end());
|
||||
using ThrottlingArray = std::array<float, static_cast<size_t>(kThrottlingSeverityCount)>;
|
||||
using CdevArray = std::array<int, static_cast<size_t>(kThrottlingSeverityCount)>;
|
||||
constexpr std::chrono::milliseconds kMinPollIntervalMs = std::chrono::milliseconds(2000);
|
||||
constexpr std::chrono::milliseconds kUeventPollTimeoutMs = std::chrono::milliseconds(300000);
|
||||
// Max number of time_in_state buckets is 20 in atoms
|
||||
// VendorSensorCoolingDeviceStats, VendorTempResidencyStats
|
||||
constexpr int kMaxStatsResidencyCount = 20;
|
||||
constexpr int kMaxStatsThresholdCount = kMaxStatsResidencyCount - 1;
|
||||
|
||||
enum FormulaOption : uint32_t {
|
||||
COUNT_THRESHOLD = 0,
|
||||
WEIGHTED_AVG,
|
||||
MAXIMUM,
|
||||
MINIMUM,
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ThresholdList {
|
||||
std::optional<std::string> logging_name;
|
||||
std::vector<T> thresholds;
|
||||
explicit ThresholdList(std::optional<std::string> logging_name, std::vector<T> thresholds)
|
||||
: logging_name(logging_name), thresholds(thresholds) {}
|
||||
|
||||
ThresholdList() = default;
|
||||
ThresholdList(const ThresholdList &) = default;
|
||||
ThresholdList &operator=(const ThresholdList &) = default;
|
||||
ThresholdList(ThresholdList &&) = default;
|
||||
ThresholdList &operator=(ThresholdList &&) = default;
|
||||
~ThresholdList() = default;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct StatsInfo {
|
||||
// if bool, record all or none depending on flag
|
||||
// if set, check name present in set
|
||||
std::variant<bool, std::unordered_set<std::string> >
|
||||
record_by_default_threshold_all_or_name_set_;
|
||||
// map name to list of thresholds
|
||||
std::unordered_map<std::string, std::vector<ThresholdList<T> > > record_by_threshold;
|
||||
void clear() {
|
||||
record_by_default_threshold_all_or_name_set_ = false;
|
||||
record_by_threshold.clear();
|
||||
}
|
||||
};
|
||||
|
||||
struct StatsConfig {
|
||||
StatsInfo<float> sensor_stats_info;
|
||||
StatsInfo<int> cooling_device_request_info;
|
||||
void clear() {
|
||||
sensor_stats_info.clear();
|
||||
cooling_device_request_info.clear();
|
||||
}
|
||||
};
|
||||
|
||||
enum SensorFusionType : uint32_t {
|
||||
SENSOR = 0,
|
||||
ODPM,
|
||||
};
|
||||
|
||||
struct VirtualSensorInfo {
|
||||
std::vector<std::string> linked_sensors;
|
||||
std::vector<SensorFusionType> linked_sensors_type;
|
||||
std::vector<float> coefficients;
|
||||
float offset;
|
||||
std::vector<std::string> trigger_sensors;
|
||||
FormulaOption formula;
|
||||
};
|
||||
|
||||
struct VirtualPowerRailInfo {
|
||||
std::vector<std::string> linked_power_rails;
|
||||
std::vector<float> coefficients;
|
||||
float offset;
|
||||
FormulaOption formula;
|
||||
};
|
||||
|
||||
// The method when the ODPM power is lower than threshold
|
||||
enum ReleaseLogic : uint32_t {
|
||||
INCREASE = 0, // Increase throttling by step
|
||||
DECREASE, // Decrease throttling by step
|
||||
STEPWISE, // Support both increase and decrease logix
|
||||
RELEASE_TO_FLOOR, // Release throttling to floor directly
|
||||
NONE,
|
||||
};
|
||||
|
||||
struct BindedCdevInfo {
|
||||
CdevArray limit_info;
|
||||
ThrottlingArray power_thresholds;
|
||||
ReleaseLogic release_logic;
|
||||
ThrottlingArray cdev_weight_for_pid;
|
||||
CdevArray cdev_ceiling;
|
||||
int max_release_step;
|
||||
int max_throttle_step;
|
||||
CdevArray cdev_floor_with_power_link;
|
||||
std::string power_rail;
|
||||
// The flag for activate release logic when power is higher than power threshold
|
||||
bool high_power_check;
|
||||
// The flag for only triggering throttling until all power samples are collected
|
||||
bool throttling_with_power_link;
|
||||
};
|
||||
|
||||
struct ThrottlingInfo {
|
||||
ThrottlingArray k_po;
|
||||
ThrottlingArray k_pu;
|
||||
ThrottlingArray k_i;
|
||||
ThrottlingArray k_d;
|
||||
ThrottlingArray i_max;
|
||||
ThrottlingArray max_alloc_power;
|
||||
ThrottlingArray min_alloc_power;
|
||||
ThrottlingArray s_power;
|
||||
ThrottlingArray i_cutoff;
|
||||
float i_default;
|
||||
int tran_cycle;
|
||||
std::unordered_map<std::string, ThrottlingArray> excluded_power_info_map;
|
||||
std::unordered_map<std::string, BindedCdevInfo> binded_cdev_info_map;
|
||||
};
|
||||
|
||||
struct SensorInfo {
|
||||
TemperatureType type;
|
||||
ThrottlingArray hot_thresholds;
|
||||
ThrottlingArray cold_thresholds;
|
||||
ThrottlingArray hot_hysteresis;
|
||||
ThrottlingArray cold_hysteresis;
|
||||
std::string temp_path;
|
||||
float vr_threshold;
|
||||
float multiplier;
|
||||
std::chrono::milliseconds polling_delay;
|
||||
std::chrono::milliseconds passive_delay;
|
||||
std::chrono::milliseconds time_resolution;
|
||||
bool send_cb;
|
||||
bool send_powerhint;
|
||||
bool is_watch;
|
||||
bool is_hidden;
|
||||
std::unique_ptr<VirtualSensorInfo> virtual_sensor_info;
|
||||
std::shared_ptr<ThrottlingInfo> throttling_info;
|
||||
};
|
||||
|
||||
struct CdevInfo {
|
||||
CoolingType type;
|
||||
std::string read_path;
|
||||
std::string write_path;
|
||||
std::vector<float> state2power;
|
||||
int max_state;
|
||||
};
|
||||
|
||||
struct PowerRailInfo {
|
||||
std::string rail;
|
||||
int power_sample_count;
|
||||
std::chrono::milliseconds power_sample_delay;
|
||||
std::unique_ptr<VirtualPowerRailInfo> virtual_power_rail_info;
|
||||
};
|
||||
|
||||
bool ParseThermalConfig(std::string_view config_path, Json::Value *config);
|
||||
bool ParseSensorInfo(const Json::Value &config,
|
||||
std::unordered_map<std::string, SensorInfo> *sensors_parsed);
|
||||
bool ParseCoolingDevice(const Json::Value &config,
|
||||
std::unordered_map<std::string, CdevInfo> *cooling_device_parsed);
|
||||
bool ParsePowerRailInfo(const Json::Value &config,
|
||||
std::unordered_map<std::string, PowerRailInfo> *power_rail_parsed);
|
||||
bool ParseStatsConfig(const Json::Value &config,
|
||||
const std::unordered_map<std::string, SensorInfo> &sensor_info_map_,
|
||||
const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map_,
|
||||
StatsConfig *stats_config);
|
||||
} // namespace implementation
|
||||
} // namespace thermal
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -1,763 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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_THERMAL | ATRACE_TAG_HAL)
|
||||
|
||||
#include "thermal_throttling.h"
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <utils/Trace.h>
|
||||
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "power_files.h"
|
||||
#include "thermal_info.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace thermal {
|
||||
namespace implementation {
|
||||
using ::android::base::StringPrintf;
|
||||
|
||||
// To find the next PID target state according to the current thermal severity
|
||||
size_t getTargetStateOfPID(const SensorInfo &sensor_info, const ThrottlingSeverity curr_severity) {
|
||||
size_t target_state = 0;
|
||||
|
||||
for (const auto &severity : ::ndk::enum_range<ThrottlingSeverity>()) {
|
||||
size_t state = static_cast<size_t>(severity);
|
||||
if (std::isnan(sensor_info.throttling_info->s_power[state])) {
|
||||
continue;
|
||||
}
|
||||
target_state = state;
|
||||
if (severity > curr_severity) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
LOG(VERBOSE) << "PID target state = " << target_state;
|
||||
return target_state;
|
||||
}
|
||||
|
||||
void ThermalThrottling::clearThrottlingData(std::string_view sensor_name,
|
||||
const SensorInfo &sensor_info) {
|
||||
if (!thermal_throttling_status_map_.count(sensor_name.data())) {
|
||||
return;
|
||||
}
|
||||
std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
|
||||
|
||||
for (auto &pid_power_budget_pair :
|
||||
thermal_throttling_status_map_.at(sensor_name.data()).pid_power_budget_map) {
|
||||
pid_power_budget_pair.second = std::numeric_limits<int>::max();
|
||||
}
|
||||
|
||||
for (auto &pid_cdev_request_pair :
|
||||
thermal_throttling_status_map_.at(sensor_name.data()).pid_cdev_request_map) {
|
||||
pid_cdev_request_pair.second = 0;
|
||||
}
|
||||
|
||||
for (auto &hardlimit_cdev_request_pair :
|
||||
thermal_throttling_status_map_.at(sensor_name.data()).hardlimit_cdev_request_map) {
|
||||
hardlimit_cdev_request_pair.second = 0;
|
||||
}
|
||||
|
||||
for (auto &throttling_release_pair :
|
||||
thermal_throttling_status_map_.at(sensor_name.data()).throttling_release_map) {
|
||||
throttling_release_pair.second = 0;
|
||||
}
|
||||
|
||||
thermal_throttling_status_map_[sensor_name.data()].prev_err = NAN;
|
||||
thermal_throttling_status_map_[sensor_name.data()].i_budget =
|
||||
sensor_info.throttling_info->i_default;
|
||||
thermal_throttling_status_map_[sensor_name.data()].prev_target =
|
||||
static_cast<size_t>(ThrottlingSeverity::NONE);
|
||||
thermal_throttling_status_map_[sensor_name.data()].prev_power_budget = NAN;
|
||||
thermal_throttling_status_map_[sensor_name.data()].tran_cycle = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool ThermalThrottling::registerThermalThrottling(
|
||||
std::string_view sensor_name, const std::shared_ptr<ThrottlingInfo> &throttling_info,
|
||||
const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map) {
|
||||
if (thermal_throttling_status_map_.count(sensor_name.data())) {
|
||||
LOG(ERROR) << "Sensor " << sensor_name.data() << " throttling map has been registered";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (throttling_info == nullptr) {
|
||||
LOG(ERROR) << "Sensor " << sensor_name.data() << " has no throttling info";
|
||||
return false;
|
||||
}
|
||||
|
||||
thermal_throttling_status_map_[sensor_name.data()].prev_err = NAN;
|
||||
thermal_throttling_status_map_[sensor_name.data()].i_budget = throttling_info->i_default;
|
||||
thermal_throttling_status_map_[sensor_name.data()].prev_target =
|
||||
static_cast<size_t>(ThrottlingSeverity::NONE);
|
||||
thermal_throttling_status_map_[sensor_name.data()].prev_power_budget = NAN;
|
||||
thermal_throttling_status_map_[sensor_name.data()].tran_cycle = 0;
|
||||
|
||||
for (auto &binded_cdev_pair : throttling_info->binded_cdev_info_map) {
|
||||
if (!cooling_device_info_map.count(binded_cdev_pair.first)) {
|
||||
LOG(ERROR) << "Could not find " << sensor_name.data() << "'s binded CDEV "
|
||||
<< binded_cdev_pair.first;
|
||||
return false;
|
||||
}
|
||||
// Register PID throttling map
|
||||
for (const auto &cdev_weight : binded_cdev_pair.second.cdev_weight_for_pid) {
|
||||
if (!std::isnan(cdev_weight)) {
|
||||
thermal_throttling_status_map_[sensor_name.data()]
|
||||
.pid_power_budget_map[binded_cdev_pair.first] =
|
||||
std::numeric_limits<int>::max();
|
||||
thermal_throttling_status_map_[sensor_name.data()]
|
||||
.pid_cdev_request_map[binded_cdev_pair.first] = 0;
|
||||
thermal_throttling_status_map_[sensor_name.data()]
|
||||
.cdev_status_map[binded_cdev_pair.first] = 0;
|
||||
cdev_all_request_map_[binded_cdev_pair.first].insert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Register hard limit throttling map
|
||||
for (const auto &limit_info : binded_cdev_pair.second.limit_info) {
|
||||
if (limit_info > 0) {
|
||||
thermal_throttling_status_map_[sensor_name.data()]
|
||||
.hardlimit_cdev_request_map[binded_cdev_pair.first] = 0;
|
||||
thermal_throttling_status_map_[sensor_name.data()]
|
||||
.cdev_status_map[binded_cdev_pair.first] = 0;
|
||||
cdev_all_request_map_[binded_cdev_pair.first].insert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Register throttling release map if power threshold exists
|
||||
if (!binded_cdev_pair.second.power_rail.empty()) {
|
||||
for (const auto &power_threshold : binded_cdev_pair.second.power_thresholds) {
|
||||
if (!std::isnan(power_threshold)) {
|
||||
thermal_throttling_status_map_[sensor_name.data()]
|
||||
.throttling_release_map[binded_cdev_pair.first] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// return power budget based on PID algo
|
||||
float ThermalThrottling::updatePowerBudget(const Temperature &temp, const SensorInfo &sensor_info,
|
||||
std::chrono::milliseconds time_elapsed_ms,
|
||||
ThrottlingSeverity curr_severity) {
|
||||
float p = 0, d = 0;
|
||||
float power_budget = std::numeric_limits<float>::max();
|
||||
bool target_changed = false;
|
||||
float budget_transient = 0.0;
|
||||
auto &throttling_status = thermal_throttling_status_map_.at(temp.name);
|
||||
std::string sensor_name = temp.name;
|
||||
|
||||
if (curr_severity == ThrottlingSeverity::NONE) {
|
||||
return power_budget;
|
||||
}
|
||||
|
||||
const auto target_state = getTargetStateOfPID(sensor_info, curr_severity);
|
||||
if (throttling_status.prev_target != static_cast<size_t>(ThrottlingSeverity::NONE) &&
|
||||
target_state != throttling_status.prev_target &&
|
||||
sensor_info.throttling_info->tran_cycle > 0) {
|
||||
throttling_status.tran_cycle = sensor_info.throttling_info->tran_cycle - 1;
|
||||
target_changed = true;
|
||||
}
|
||||
throttling_status.prev_target = target_state;
|
||||
|
||||
// Compute PID
|
||||
float err = sensor_info.hot_thresholds[target_state] - temp.value;
|
||||
p = err * (err < 0 ? sensor_info.throttling_info->k_po[target_state]
|
||||
: sensor_info.throttling_info->k_pu[target_state]);
|
||||
|
||||
if (err < sensor_info.throttling_info->i_cutoff[target_state]) {
|
||||
throttling_status.i_budget += err * sensor_info.throttling_info->k_i[target_state];
|
||||
}
|
||||
|
||||
if (fabsf(throttling_status.i_budget) > sensor_info.throttling_info->i_max[target_state]) {
|
||||
throttling_status.i_budget = sensor_info.throttling_info->i_max[target_state] *
|
||||
(throttling_status.i_budget > 0 ? 1 : -1);
|
||||
}
|
||||
|
||||
if (!std::isnan(throttling_status.prev_err) &&
|
||||
time_elapsed_ms != std::chrono::milliseconds::zero()) {
|
||||
d = sensor_info.throttling_info->k_d[target_state] * (err - throttling_status.prev_err) /
|
||||
time_elapsed_ms.count();
|
||||
}
|
||||
|
||||
throttling_status.prev_err = err;
|
||||
// Calculate power budget
|
||||
power_budget =
|
||||
sensor_info.throttling_info->s_power[target_state] + p + throttling_status.i_budget + d;
|
||||
if (power_budget < sensor_info.throttling_info->min_alloc_power[target_state]) {
|
||||
power_budget = sensor_info.throttling_info->min_alloc_power[target_state];
|
||||
}
|
||||
if (power_budget > sensor_info.throttling_info->max_alloc_power[target_state]) {
|
||||
power_budget = sensor_info.throttling_info->max_alloc_power[target_state];
|
||||
}
|
||||
|
||||
if (target_changed) {
|
||||
throttling_status.budget_transient = throttling_status.prev_power_budget - power_budget;
|
||||
}
|
||||
|
||||
if (throttling_status.tran_cycle) {
|
||||
budget_transient = throttling_status.budget_transient *
|
||||
((static_cast<float>(throttling_status.tran_cycle) /
|
||||
static_cast<float>(sensor_info.throttling_info->tran_cycle)));
|
||||
power_budget += budget_transient;
|
||||
throttling_status.tran_cycle--;
|
||||
}
|
||||
|
||||
LOG(INFO) << temp.name << " power_budget=" << power_budget << " err=" << err
|
||||
<< " s_power=" << sensor_info.throttling_info->s_power[target_state]
|
||||
<< " time_elapsed_ms=" << time_elapsed_ms.count() << " p=" << p
|
||||
<< " i=" << throttling_status.i_budget << " d=" << d
|
||||
<< " budget transient=" << budget_transient << " control target=" << target_state;
|
||||
|
||||
ATRACE_INT((sensor_name + std::string("-power_budget")).c_str(),
|
||||
static_cast<int>(power_budget));
|
||||
ATRACE_INT((sensor_name + std::string("-s_power")).c_str(),
|
||||
static_cast<int>(sensor_info.throttling_info->s_power[target_state]));
|
||||
ATRACE_INT((sensor_name + std::string("-time_elapsed_ms")).c_str(),
|
||||
static_cast<int>(time_elapsed_ms.count()));
|
||||
ATRACE_INT((sensor_name + std::string("-budget_transient")).c_str(),
|
||||
static_cast<int>(budget_transient));
|
||||
ATRACE_INT((sensor_name + std::string("-i")).c_str(),
|
||||
static_cast<int>(throttling_status.i_budget));
|
||||
ATRACE_INT((sensor_name + std::string("-target_state")).c_str(),
|
||||
static_cast<int>(target_state));
|
||||
|
||||
ATRACE_INT((sensor_name + std::string("-err")).c_str(), static_cast<int>(err / sensor_info.multiplier));
|
||||
ATRACE_INT((sensor_name + std::string("-p")).c_str(), static_cast<int>(p));
|
||||
ATRACE_INT((sensor_name + std::string("-d")).c_str(), static_cast<int>(d));
|
||||
ATRACE_INT((sensor_name + std::string("-temp")).c_str(), static_cast<int>(temp.value / sensor_info.multiplier));
|
||||
|
||||
throttling_status.prev_power_budget = power_budget;
|
||||
|
||||
return power_budget;
|
||||
}
|
||||
|
||||
float ThermalThrottling::computeExcludedPower(
|
||||
const SensorInfo &sensor_info, const ThrottlingSeverity curr_severity,
|
||||
const std::unordered_map<std::string, PowerStatus> &power_status_map, std::string *log_buf,
|
||||
std::string_view sensor_name) {
|
||||
float excluded_power = 0.0;
|
||||
|
||||
for (const auto &excluded_power_info_pair :
|
||||
sensor_info.throttling_info->excluded_power_info_map) {
|
||||
const auto last_updated_avg_power =
|
||||
power_status_map.at(excluded_power_info_pair.first).last_updated_avg_power;
|
||||
if (!std::isnan(last_updated_avg_power)) {
|
||||
excluded_power += last_updated_avg_power *
|
||||
excluded_power_info_pair.second[static_cast<size_t>(curr_severity)];
|
||||
log_buf->append(StringPrintf(
|
||||
"(%s: %0.2f mW, cdev_weight: %f)", excluded_power_info_pair.first.c_str(),
|
||||
last_updated_avg_power,
|
||||
excluded_power_info_pair.second[static_cast<size_t>(curr_severity)]));
|
||||
|
||||
ATRACE_INT((std::string(sensor_name) + std::string("-") +
|
||||
excluded_power_info_pair.first + std::string("-avg_power"))
|
||||
.c_str(),
|
||||
static_cast<int>(last_updated_avg_power));
|
||||
}
|
||||
}
|
||||
|
||||
ATRACE_INT((std::string(sensor_name) + std::string("-excluded_power")).c_str(),
|
||||
static_cast<int>(excluded_power));
|
||||
return excluded_power;
|
||||
}
|
||||
|
||||
// Allocate power budget to binded cooling devices base on the real ODPM power data
|
||||
bool ThermalThrottling::allocatePowerToCdev(
|
||||
const Temperature &temp, const SensorInfo &sensor_info,
|
||||
const ThrottlingSeverity curr_severity, const std::chrono::milliseconds time_elapsed_ms,
|
||||
const std::unordered_map<std::string, PowerStatus> &power_status_map,
|
||||
const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map) {
|
||||
float total_weight = 0;
|
||||
float last_updated_avg_power = NAN;
|
||||
float allocated_power = 0;
|
||||
float allocated_weight = 0;
|
||||
bool low_power_device_check = true;
|
||||
bool is_budget_allocated = false;
|
||||
bool power_data_invalid = false;
|
||||
std::set<std::string> allocated_cdev;
|
||||
std::string log_buf;
|
||||
|
||||
std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
|
||||
auto total_power_budget = updatePowerBudget(temp, sensor_info, time_elapsed_ms, curr_severity);
|
||||
|
||||
if (sensor_info.throttling_info->excluded_power_info_map.size()) {
|
||||
total_power_budget -= computeExcludedPower(sensor_info, curr_severity, power_status_map,
|
||||
&log_buf, temp.name);
|
||||
total_power_budget = std::max(total_power_budget, 0.0f);
|
||||
if (!log_buf.empty()) {
|
||||
LOG(INFO) << temp.name << " power budget=" << total_power_budget << " after " << log_buf
|
||||
<< " is excluded";
|
||||
}
|
||||
}
|
||||
|
||||
// Compute total cdev weight
|
||||
for (const auto &binded_cdev_info_pair : sensor_info.throttling_info->binded_cdev_info_map) {
|
||||
const auto cdev_weight = binded_cdev_info_pair.second
|
||||
.cdev_weight_for_pid[static_cast<size_t>(curr_severity)];
|
||||
if (std::isnan(cdev_weight) || cdev_weight == 0) {
|
||||
allocated_cdev.insert(binded_cdev_info_pair.first);
|
||||
continue;
|
||||
}
|
||||
total_weight += cdev_weight;
|
||||
}
|
||||
|
||||
while (!is_budget_allocated) {
|
||||
for (const auto &binded_cdev_info_pair :
|
||||
sensor_info.throttling_info->binded_cdev_info_map) {
|
||||
float cdev_power_adjustment = 0;
|
||||
const auto cdev_weight =
|
||||
binded_cdev_info_pair.second
|
||||
.cdev_weight_for_pid[static_cast<size_t>(curr_severity)];
|
||||
|
||||
if (allocated_cdev.count(binded_cdev_info_pair.first)) {
|
||||
continue;
|
||||
}
|
||||
if (std::isnan(cdev_weight) || !cdev_weight) {
|
||||
allocated_cdev.insert(binded_cdev_info_pair.first);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the power data
|
||||
if (!power_data_invalid) {
|
||||
if (!binded_cdev_info_pair.second.power_rail.empty()) {
|
||||
last_updated_avg_power =
|
||||
power_status_map.at(binded_cdev_info_pair.second.power_rail)
|
||||
.last_updated_avg_power;
|
||||
if (std::isnan(last_updated_avg_power)) {
|
||||
LOG(VERBOSE) << "power data is under collecting";
|
||||
power_data_invalid = true;
|
||||
break;
|
||||
}
|
||||
|
||||
ATRACE_INT((temp.name + std::string("-") +
|
||||
binded_cdev_info_pair.second.power_rail + std::string("-avg_power"))
|
||||
.c_str(),
|
||||
static_cast<int>(last_updated_avg_power));
|
||||
} else {
|
||||
power_data_invalid = true;
|
||||
break;
|
||||
}
|
||||
if (binded_cdev_info_pair.second.throttling_with_power_link) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto cdev_power_budget = total_power_budget * (cdev_weight / total_weight);
|
||||
cdev_power_adjustment = cdev_power_budget - last_updated_avg_power;
|
||||
|
||||
if (low_power_device_check) {
|
||||
// Share the budget for the CDEV which power is lower than target
|
||||
if (cdev_power_adjustment > 0 &&
|
||||
thermal_throttling_status_map_[temp.name].pid_cdev_request_map.at(
|
||||
binded_cdev_info_pair.first) == 0) {
|
||||
allocated_power += last_updated_avg_power;
|
||||
allocated_weight += cdev_weight;
|
||||
allocated_cdev.insert(binded_cdev_info_pair.first);
|
||||
if (!binded_cdev_info_pair.second.power_rail.empty()) {
|
||||
log_buf.append(StringPrintf("(%s: %0.2f mW)",
|
||||
binded_cdev_info_pair.second.power_rail.c_str(),
|
||||
last_updated_avg_power));
|
||||
}
|
||||
LOG(VERBOSE) << temp.name << " binded " << binded_cdev_info_pair.first
|
||||
<< " has been already at min state 0";
|
||||
}
|
||||
} else {
|
||||
const CdevInfo &cdev_info = cooling_device_info_map.at(binded_cdev_info_pair.first);
|
||||
if (!binded_cdev_info_pair.second.power_rail.empty()) {
|
||||
log_buf.append(StringPrintf("(%s: %0.2f mW)",
|
||||
binded_cdev_info_pair.second.power_rail.c_str(),
|
||||
last_updated_avg_power));
|
||||
}
|
||||
// Ignore the power distribution if the CDEV has no space to reduce power
|
||||
if ((cdev_power_adjustment < 0 &&
|
||||
thermal_throttling_status_map_[temp.name].pid_cdev_request_map.at(
|
||||
binded_cdev_info_pair.first) == cdev_info.max_state)) {
|
||||
LOG(VERBOSE) << temp.name << " binded " << binded_cdev_info_pair.first
|
||||
<< " has been already at max state " << cdev_info.max_state;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!power_data_invalid && binded_cdev_info_pair.second.power_rail != "") {
|
||||
auto cdev_curr_power_budget =
|
||||
thermal_throttling_status_map_[temp.name].pid_power_budget_map.at(
|
||||
binded_cdev_info_pair.first);
|
||||
|
||||
if (last_updated_avg_power > cdev_curr_power_budget) {
|
||||
cdev_power_budget = cdev_curr_power_budget +=
|
||||
(cdev_power_adjustment *
|
||||
(cdev_curr_power_budget / last_updated_avg_power));
|
||||
} else {
|
||||
cdev_power_budget = cdev_curr_power_budget += cdev_power_adjustment;
|
||||
}
|
||||
} else {
|
||||
cdev_power_budget = total_power_budget * (cdev_weight / total_weight);
|
||||
}
|
||||
|
||||
if (!std::isnan(cdev_info.state2power[0]) &&
|
||||
cdev_power_budget > cdev_info.state2power[0]) {
|
||||
cdev_power_budget = cdev_info.state2power[0];
|
||||
} else if (cdev_power_budget < 0) {
|
||||
cdev_power_budget = 0;
|
||||
}
|
||||
|
||||
int max_cdev_vote;
|
||||
if (!getCdevMaxRequest(binded_cdev_info_pair.first, &max_cdev_vote)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto curr_cdev_vote =
|
||||
thermal_throttling_status_map_[temp.name].pid_cdev_request_map.at(
|
||||
binded_cdev_info_pair.first);
|
||||
|
||||
if (binded_cdev_info_pair.second.max_release_step !=
|
||||
std::numeric_limits<int>::max() &&
|
||||
(power_data_invalid || cdev_power_adjustment > 0)) {
|
||||
if (!power_data_invalid && curr_cdev_vote < max_cdev_vote) {
|
||||
cdev_power_budget = cdev_info.state2power[curr_cdev_vote];
|
||||
LOG(VERBOSE) << temp.name << "'s " << binded_cdev_info_pair.first
|
||||
<< " vote: " << curr_cdev_vote
|
||||
<< " is lower than max cdev vote: " << max_cdev_vote;
|
||||
} else {
|
||||
const auto target_state = std::max(
|
||||
curr_cdev_vote - binded_cdev_info_pair.second.max_release_step, 0);
|
||||
cdev_power_budget =
|
||||
std::min(cdev_power_budget, cdev_info.state2power[target_state]);
|
||||
}
|
||||
}
|
||||
|
||||
if (binded_cdev_info_pair.second.max_throttle_step !=
|
||||
std::numeric_limits<int>::max() &&
|
||||
(power_data_invalid || cdev_power_adjustment < 0)) {
|
||||
const auto target_state = std::min(
|
||||
curr_cdev_vote + binded_cdev_info_pair.second.max_throttle_step,
|
||||
cdev_info.max_state);
|
||||
cdev_power_budget =
|
||||
std::max(cdev_power_budget, cdev_info.state2power[target_state]);
|
||||
}
|
||||
|
||||
thermal_throttling_status_map_[temp.name].pid_power_budget_map.at(
|
||||
binded_cdev_info_pair.first) = cdev_power_budget;
|
||||
LOG(VERBOSE) << temp.name << " allocate "
|
||||
<< thermal_throttling_status_map_[temp.name].pid_power_budget_map.at(
|
||||
binded_cdev_info_pair.first)
|
||||
<< "mW to " << binded_cdev_info_pair.first
|
||||
<< "(cdev_weight=" << cdev_weight << ")";
|
||||
}
|
||||
}
|
||||
|
||||
if (!power_data_invalid) {
|
||||
total_power_budget -= allocated_power;
|
||||
total_weight -= allocated_weight;
|
||||
}
|
||||
allocated_power = 0;
|
||||
allocated_weight = 0;
|
||||
|
||||
if (low_power_device_check) {
|
||||
low_power_device_check = false;
|
||||
} else {
|
||||
is_budget_allocated = true;
|
||||
}
|
||||
}
|
||||
if (log_buf.size()) {
|
||||
LOG(INFO) << temp.name << " binded power rails: " << log_buf;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ThermalThrottling::updateCdevRequestByPower(
|
||||
std::string sensor_name,
|
||||
const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map) {
|
||||
size_t i;
|
||||
|
||||
std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
|
||||
for (auto &pid_power_budget_pair :
|
||||
thermal_throttling_status_map_[sensor_name.data()].pid_power_budget_map) {
|
||||
const CdevInfo &cdev_info = cooling_device_info_map.at(pid_power_budget_pair.first);
|
||||
|
||||
for (i = 0; i < cdev_info.state2power.size() - 1; ++i) {
|
||||
if (pid_power_budget_pair.second >= cdev_info.state2power[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
thermal_throttling_status_map_[sensor_name.data()].pid_cdev_request_map.at(
|
||||
pid_power_budget_pair.first) = static_cast<int>(i);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void ThermalThrottling::updateCdevRequestBySeverity(std::string_view sensor_name,
|
||||
const SensorInfo &sensor_info,
|
||||
ThrottlingSeverity curr_severity) {
|
||||
std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
|
||||
for (auto const &binded_cdev_info_pair : sensor_info.throttling_info->binded_cdev_info_map) {
|
||||
thermal_throttling_status_map_[sensor_name.data()].hardlimit_cdev_request_map.at(
|
||||
binded_cdev_info_pair.first) =
|
||||
binded_cdev_info_pair.second.limit_info[static_cast<size_t>(curr_severity)];
|
||||
LOG(VERBOSE) << "Hard Limit: Sensor " << sensor_name.data() << " update cdev "
|
||||
<< binded_cdev_info_pair.first << " to "
|
||||
<< thermal_throttling_status_map_[sensor_name.data()]
|
||||
.hardlimit_cdev_request_map.at(binded_cdev_info_pair.first);
|
||||
}
|
||||
}
|
||||
|
||||
bool ThermalThrottling::throttlingReleaseUpdate(
|
||||
std::string_view sensor_name,
|
||||
const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map,
|
||||
const std::unordered_map<std::string, PowerStatus> &power_status_map,
|
||||
const ThrottlingSeverity severity, const SensorInfo &sensor_info) {
|
||||
ATRACE_CALL();
|
||||
std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
|
||||
if (!thermal_throttling_status_map_.count(sensor_name.data())) {
|
||||
return false;
|
||||
}
|
||||
auto &thermal_throttling_status = thermal_throttling_status_map_.at(sensor_name.data());
|
||||
for (const auto &binded_cdev_info_pair : sensor_info.throttling_info->binded_cdev_info_map) {
|
||||
float avg_power = -1;
|
||||
|
||||
if (!thermal_throttling_status.throttling_release_map.count(binded_cdev_info_pair.first) ||
|
||||
!power_status_map.count(binded_cdev_info_pair.second.power_rail)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto max_state = cooling_device_info_map.at(binded_cdev_info_pair.first).max_state;
|
||||
|
||||
auto &release_step =
|
||||
thermal_throttling_status.throttling_release_map.at(binded_cdev_info_pair.first);
|
||||
avg_power =
|
||||
power_status_map.at(binded_cdev_info_pair.second.power_rail).last_updated_avg_power;
|
||||
|
||||
if (std::isnan(avg_power) || avg_power < 0) {
|
||||
release_step = binded_cdev_info_pair.second.throttling_with_power_link ? max_state : 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool is_over_budget = true;
|
||||
if (!binded_cdev_info_pair.second.high_power_check) {
|
||||
if (avg_power <
|
||||
binded_cdev_info_pair.second.power_thresholds[static_cast<int>(severity)]) {
|
||||
is_over_budget = false;
|
||||
}
|
||||
} else {
|
||||
if (avg_power >
|
||||
binded_cdev_info_pair.second.power_thresholds[static_cast<int>(severity)]) {
|
||||
is_over_budget = false;
|
||||
}
|
||||
}
|
||||
LOG(INFO) << sensor_name.data() << "'s " << binded_cdev_info_pair.first
|
||||
<< " binded power rail " << binded_cdev_info_pair.second.power_rail
|
||||
<< ": power threshold = "
|
||||
<< binded_cdev_info_pair.second.power_thresholds[static_cast<int>(severity)]
|
||||
<< ", avg power = " << avg_power;
|
||||
std::string atrace_prefix = ::android::base::StringPrintf(
|
||||
"%s-%s", sensor_name.data(), binded_cdev_info_pair.second.power_rail.data());
|
||||
ATRACE_INT(
|
||||
(atrace_prefix + std::string("-power_threshold")).c_str(),
|
||||
static_cast<int>(
|
||||
binded_cdev_info_pair.second.power_thresholds[static_cast<int>(severity)]));
|
||||
ATRACE_INT((atrace_prefix + std::string("-avg_power")).c_str(), avg_power);
|
||||
|
||||
switch (binded_cdev_info_pair.second.release_logic) {
|
||||
case ReleaseLogic::INCREASE:
|
||||
if (!is_over_budget) {
|
||||
if (std::abs(release_step) < static_cast<int>(max_state)) {
|
||||
release_step--;
|
||||
}
|
||||
} else {
|
||||
release_step = 0;
|
||||
}
|
||||
break;
|
||||
case ReleaseLogic::DECREASE:
|
||||
if (!is_over_budget) {
|
||||
if (release_step < static_cast<int>(max_state)) {
|
||||
release_step++;
|
||||
}
|
||||
} else {
|
||||
release_step = 0;
|
||||
}
|
||||
break;
|
||||
case ReleaseLogic::STEPWISE:
|
||||
if (!is_over_budget) {
|
||||
if (release_step < static_cast<int>(max_state)) {
|
||||
release_step++;
|
||||
}
|
||||
} else {
|
||||
if (std::abs(release_step) < static_cast<int>(max_state)) {
|
||||
release_step--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ReleaseLogic::RELEASE_TO_FLOOR:
|
||||
release_step = is_over_budget ? 0 : max_state;
|
||||
break;
|
||||
case ReleaseLogic::NONE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ThermalThrottling::thermalThrottlingUpdate(
|
||||
const Temperature &temp, const SensorInfo &sensor_info,
|
||||
const ThrottlingSeverity curr_severity, const std::chrono::milliseconds time_elapsed_ms,
|
||||
const std::unordered_map<std::string, PowerStatus> &power_status_map,
|
||||
const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map) {
|
||||
if (!thermal_throttling_status_map_.count(temp.name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (thermal_throttling_status_map_[temp.name].pid_power_budget_map.size()) {
|
||||
if (!allocatePowerToCdev(temp, sensor_info, curr_severity, time_elapsed_ms,
|
||||
power_status_map, cooling_device_info_map)) {
|
||||
LOG(ERROR) << "Sensor " << temp.name << " PID request cdev failed";
|
||||
// Clear the CDEV request if the power budget is failed to be allocated
|
||||
for (auto &pid_cdev_request_pair :
|
||||
thermal_throttling_status_map_[temp.name].pid_cdev_request_map) {
|
||||
pid_cdev_request_pair.second = 0;
|
||||
}
|
||||
}
|
||||
updateCdevRequestByPower(temp.name, cooling_device_info_map);
|
||||
}
|
||||
|
||||
if (thermal_throttling_status_map_[temp.name].hardlimit_cdev_request_map.size()) {
|
||||
updateCdevRequestBySeverity(temp.name.c_str(), sensor_info, curr_severity);
|
||||
}
|
||||
|
||||
if (thermal_throttling_status_map_[temp.name].throttling_release_map.size()) {
|
||||
throttlingReleaseUpdate(temp.name.c_str(), cooling_device_info_map, power_status_map,
|
||||
curr_severity, sensor_info);
|
||||
}
|
||||
}
|
||||
|
||||
void ThermalThrottling::computeCoolingDevicesRequest(
|
||||
std::string_view sensor_name, const SensorInfo &sensor_info,
|
||||
const ThrottlingSeverity curr_severity, std::vector<std::string> *cooling_devices_to_update) {
|
||||
int release_step = 0;
|
||||
std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
|
||||
|
||||
if (!thermal_throttling_status_map_.count(sensor_name.data())) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto &thermal_throttling_status = thermal_throttling_status_map_.at(sensor_name.data());
|
||||
const auto &cdev_release_map = thermal_throttling_status.throttling_release_map;
|
||||
|
||||
for (auto &cdev_request_pair : thermal_throttling_status.cdev_status_map) {
|
||||
int pid_cdev_request = 0;
|
||||
int hardlimit_cdev_request = 0;
|
||||
const auto &cdev_name = cdev_request_pair.first;
|
||||
const auto &binded_cdev_info =
|
||||
sensor_info.throttling_info->binded_cdev_info_map.at(cdev_name);
|
||||
const auto cdev_ceiling = binded_cdev_info.cdev_ceiling[static_cast<size_t>(curr_severity)];
|
||||
const auto cdev_floor =
|
||||
binded_cdev_info.cdev_floor_with_power_link[static_cast<size_t>(curr_severity)];
|
||||
release_step = 0;
|
||||
|
||||
if (thermal_throttling_status.pid_cdev_request_map.count(cdev_name)) {
|
||||
pid_cdev_request = thermal_throttling_status.pid_cdev_request_map.at(cdev_name);
|
||||
}
|
||||
|
||||
if (thermal_throttling_status.hardlimit_cdev_request_map.count(cdev_name)) {
|
||||
hardlimit_cdev_request =
|
||||
thermal_throttling_status.hardlimit_cdev_request_map.at(cdev_name);
|
||||
}
|
||||
|
||||
if (cdev_release_map.count(cdev_name)) {
|
||||
release_step = cdev_release_map.at(cdev_name);
|
||||
}
|
||||
|
||||
LOG(VERBOSE) << sensor_name.data() << " binded cooling device " << cdev_name
|
||||
<< "'s pid_request=" << pid_cdev_request
|
||||
<< " hardlimit_cdev_request=" << hardlimit_cdev_request
|
||||
<< " release_step=" << release_step
|
||||
<< " cdev_floor_with_power_link=" << cdev_floor
|
||||
<< " cdev_ceiling=" << cdev_ceiling;
|
||||
std::string atrace_prefix =
|
||||
::android::base::StringPrintf("%s-%s", sensor_name.data(), cdev_name.data());
|
||||
ATRACE_INT((atrace_prefix + std::string("-pid_request")).c_str(), pid_cdev_request);
|
||||
ATRACE_INT((atrace_prefix + std::string("-hardlimit_request")).c_str(),
|
||||
hardlimit_cdev_request);
|
||||
ATRACE_INT((atrace_prefix + std::string("-release_step")).c_str(), release_step);
|
||||
ATRACE_INT((atrace_prefix + std::string("-cdev_floor")).c_str(), cdev_floor);
|
||||
ATRACE_INT((atrace_prefix + std::string("-cdev_ceiling")).c_str(), cdev_ceiling);
|
||||
|
||||
auto request_state = std::max(pid_cdev_request, hardlimit_cdev_request);
|
||||
if (release_step) {
|
||||
if (release_step >= request_state) {
|
||||
request_state = 0;
|
||||
} else {
|
||||
request_state = request_state - release_step;
|
||||
}
|
||||
// Only check the cdev_floor when release step is non zero
|
||||
request_state = std::max(request_state, cdev_floor);
|
||||
}
|
||||
request_state = std::min(request_state, cdev_ceiling);
|
||||
if (cdev_request_pair.second != request_state) {
|
||||
if (updateCdevMaxRequestAndNotifyIfChange(cdev_name, cdev_request_pair.second,
|
||||
request_state)) {
|
||||
cooling_devices_to_update->emplace_back(cdev_name);
|
||||
}
|
||||
cdev_request_pair.second = request_state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ThermalThrottling::updateCdevMaxRequestAndNotifyIfChange(std::string_view cdev_name,
|
||||
int cur_request, int new_request) {
|
||||
std::unique_lock<std::shared_mutex> _lock(cdev_all_request_map_mutex_);
|
||||
auto &request_set = cdev_all_request_map_.at(cdev_name.data());
|
||||
int cur_max_request = (*request_set.begin());
|
||||
// Remove old cdev request and add the new one.
|
||||
request_set.erase(request_set.find(cur_request));
|
||||
request_set.insert(new_request);
|
||||
// Check if there is any change in aggregated max cdev request.
|
||||
int new_max_request = (*request_set.begin());
|
||||
LOG(VERBOSE) << "For cooling device [" << cdev_name.data()
|
||||
<< "] cur_max_request is: " << cur_max_request
|
||||
<< " new_max_request is: " << new_max_request;
|
||||
return new_max_request != cur_max_request;
|
||||
}
|
||||
|
||||
bool ThermalThrottling::getCdevMaxRequest(std::string_view cdev_name, int *max_state) {
|
||||
std::shared_lock<std::shared_mutex> _lock(cdev_all_request_map_mutex_);
|
||||
if (!cdev_all_request_map_.count(cdev_name.data())) {
|
||||
LOG(ERROR) << "Cooling device [" << cdev_name.data()
|
||||
<< "] not present in cooling device request map";
|
||||
return false;
|
||||
}
|
||||
*max_state = *cdev_all_request_map_.at(cdev_name.data()).begin();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace thermal
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -1,140 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <aidl/android/hardware/thermal/Temperature.h>
|
||||
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <shared_mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "power_files.h"
|
||||
#include "thermal_info.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace thermal {
|
||||
namespace implementation {
|
||||
|
||||
struct ThermalThrottlingStatus {
|
||||
std::unordered_map<std::string, int> pid_power_budget_map;
|
||||
std::unordered_map<std::string, int> pid_cdev_request_map;
|
||||
std::unordered_map<std::string, int> hardlimit_cdev_request_map;
|
||||
std::unordered_map<std::string, int> throttling_release_map;
|
||||
std::unordered_map<std::string, int> cdev_status_map;
|
||||
float prev_err;
|
||||
float i_budget;
|
||||
float prev_target;
|
||||
float prev_power_budget;
|
||||
float budget_transient;
|
||||
int tran_cycle;
|
||||
};
|
||||
|
||||
// Return the control temp target of PID algorithm
|
||||
size_t getTargetStateOfPID(const SensorInfo &sensor_info, const ThrottlingSeverity curr_severity);
|
||||
|
||||
// A helper class for conducting thermal throttling
|
||||
class ThermalThrottling {
|
||||
public:
|
||||
ThermalThrottling() = default;
|
||||
~ThermalThrottling() = default;
|
||||
// Disallow copy and assign.
|
||||
ThermalThrottling(const ThermalThrottling &) = delete;
|
||||
void operator=(const ThermalThrottling &) = delete;
|
||||
|
||||
// Clear throttling data
|
||||
void clearThrottlingData(std::string_view sensor_name, const SensorInfo &sensor_info);
|
||||
// Register map for throttling algo
|
||||
bool registerThermalThrottling(
|
||||
std::string_view sensor_name, const std::shared_ptr<ThrottlingInfo> &throttling_info,
|
||||
const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map);
|
||||
// Register map for throttling release algo
|
||||
bool registerThrottlingReleaseToWatch(std::string_view sensor_name, std::string_view cdev_name,
|
||||
const BindedCdevInfo &binded_cdev_info);
|
||||
// Get throttling status map
|
||||
const std::unordered_map<std::string, ThermalThrottlingStatus> &GetThermalThrottlingStatusMap()
|
||||
const {
|
||||
std::shared_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
|
||||
return thermal_throttling_status_map_;
|
||||
}
|
||||
// Update thermal throttling request for the specific sensor
|
||||
void thermalThrottlingUpdate(
|
||||
const Temperature &temp, const SensorInfo &sensor_info,
|
||||
const ThrottlingSeverity curr_severity, const std::chrono::milliseconds time_elapsed_ms,
|
||||
const std::unordered_map<std::string, PowerStatus> &power_status_map,
|
||||
const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map);
|
||||
|
||||
// Compute the throttling target from all the sensors' request
|
||||
void computeCoolingDevicesRequest(std::string_view sensor_name, const SensorInfo &sensor_info,
|
||||
const ThrottlingSeverity curr_severity,
|
||||
std::vector<std::string> *cooling_devices_to_update);
|
||||
// Get the aggregated (from all sensor) max request for a cooling device
|
||||
bool getCdevMaxRequest(std::string_view cdev_name, int *max_state);
|
||||
|
||||
private:
|
||||
// PID algo - get the total power budget
|
||||
float updatePowerBudget(const Temperature &temp, const SensorInfo &sensor_info,
|
||||
std::chrono::milliseconds time_elapsed_ms,
|
||||
ThrottlingSeverity curr_severity);
|
||||
|
||||
// PID algo - return the power number from excluded power rail list
|
||||
float computeExcludedPower(const SensorInfo &sensor_info,
|
||||
const ThrottlingSeverity curr_severity,
|
||||
const std::unordered_map<std::string, PowerStatus> &power_status_map,
|
||||
std::string *log_buf, std::string_view sensor_name);
|
||||
|
||||
// PID algo - allocate the power to target CDEV according to the ODPM
|
||||
bool allocatePowerToCdev(
|
||||
const Temperature &temp, const SensorInfo &sensor_info,
|
||||
const ThrottlingSeverity curr_severity, const std::chrono::milliseconds time_elapsed_ms,
|
||||
const std::unordered_map<std::string, PowerStatus> &power_status_map,
|
||||
const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map);
|
||||
// PID algo - map the target throttling state according to the power budget
|
||||
void updateCdevRequestByPower(
|
||||
std::string sensor_name,
|
||||
const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map);
|
||||
// Hard limit algo - assign the throttling state according to the severity
|
||||
void updateCdevRequestBySeverity(std::string_view sensor_name, const SensorInfo &sensor_info,
|
||||
ThrottlingSeverity curr_severity);
|
||||
// Throttling release algo - decide release step according to the predefined power threshold,
|
||||
// return false if the throttling release is not registered in thermal config
|
||||
bool throttlingReleaseUpdate(
|
||||
std::string_view sensor_name,
|
||||
const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map,
|
||||
const std::unordered_map<std::string, PowerStatus> &power_status_map,
|
||||
const ThrottlingSeverity severity, const SensorInfo &sensor_info);
|
||||
// Update the cooling device request set for new request and notify the caller if there is
|
||||
// change in max_request for the cooling device.
|
||||
bool updateCdevMaxRequestAndNotifyIfChange(std::string_view cdev_name, int cur_request,
|
||||
int new_request);
|
||||
mutable std::shared_mutex thermal_throttling_status_map_mutex_;
|
||||
// Thermal throttling status from each sensor
|
||||
std::unordered_map<std::string, ThermalThrottlingStatus> thermal_throttling_status_map_;
|
||||
std::shared_mutex cdev_all_request_map_mutex_;
|
||||
// Set of all request for a cooling device from each sensor
|
||||
std::unordered_map<std::string, std::multiset<int, std::greater<int>>> cdev_all_request_map_;
|
||||
};
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace thermal
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -1,533 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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_THERMAL | ATRACE_TAG_HAL)
|
||||
|
||||
#include "thermal_watcher.h"
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <cutils/uevent.h>
|
||||
#include <dirent.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/types.h>
|
||||
#include <utils/Trace.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
|
||||
#include "../thermal-helper.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace thermal {
|
||||
namespace implementation {
|
||||
|
||||
namespace {
|
||||
|
||||
static int nlErrorHandle(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) {
|
||||
int *ret = reinterpret_cast<int *>(arg);
|
||||
*ret = err->error;
|
||||
LOG(ERROR) << __func__ << "nl_groups: " << nla->nl_groups << ", nl_pid: " << nla->nl_pid;
|
||||
|
||||
return NL_STOP;
|
||||
}
|
||||
|
||||
static int nlFinishHandle(struct nl_msg *msg, void *arg) {
|
||||
int *ret = reinterpret_cast<int *>(arg);
|
||||
*ret = 1;
|
||||
struct nlmsghdr *nlh = nlmsg_hdr(msg);
|
||||
|
||||
LOG(VERBOSE) << __func__ << ": nlmsg type: " << nlh->nlmsg_type;
|
||||
|
||||
return NL_OK;
|
||||
}
|
||||
|
||||
static int nlAckHandle(struct nl_msg *msg, void *arg) {
|
||||
int *ret = reinterpret_cast<int *>(arg);
|
||||
*ret = 1;
|
||||
struct nlmsghdr *nlh = nlmsg_hdr(msg);
|
||||
|
||||
LOG(VERBOSE) << __func__ << ": nlmsg type: " << nlh->nlmsg_type;
|
||||
|
||||
return NL_OK;
|
||||
}
|
||||
|
||||
static int nlSeqCheckHandle(struct nl_msg *msg, void *arg) {
|
||||
int *ret = reinterpret_cast<int *>(arg);
|
||||
*ret = 1;
|
||||
struct nlmsghdr *nlh = nlmsg_hdr(msg);
|
||||
|
||||
LOG(VERBOSE) << __func__ << ": nlmsg type: " << nlh->nlmsg_type;
|
||||
|
||||
return NL_OK;
|
||||
}
|
||||
|
||||
struct HandlerArgs {
|
||||
const char *group;
|
||||
int id;
|
||||
};
|
||||
|
||||
static int nlSendMsg(struct nl_sock *sock, struct nl_msg *msg,
|
||||
int (*rx_handler)(struct nl_msg *, void *), void *data) {
|
||||
int err, done = 0;
|
||||
|
||||
std::unique_ptr<nl_cb, decltype(&nl_cb_put)> cb(nl_cb_alloc(NL_CB_DEFAULT), nl_cb_put);
|
||||
|
||||
err = nl_send_auto_complete(sock, msg);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = 0;
|
||||
nl_cb_err(cb.get(), NL_CB_CUSTOM, nlErrorHandle, &err);
|
||||
nl_cb_set(cb.get(), NL_CB_FINISH, NL_CB_CUSTOM, nlFinishHandle, &done);
|
||||
nl_cb_set(cb.get(), NL_CB_ACK, NL_CB_CUSTOM, nlAckHandle, &done);
|
||||
|
||||
if (rx_handler != NULL)
|
||||
nl_cb_set(cb.get(), NL_CB_VALID, NL_CB_CUSTOM, rx_handler, data);
|
||||
|
||||
while (err == 0 && done == 0) nl_recvmsgs(sock, cb.get());
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nlFamilyHandle(struct nl_msg *msg, void *arg) {
|
||||
struct HandlerArgs *grp = reinterpret_cast<struct HandlerArgs *>(arg);
|
||||
struct nlattr *tb[CTRL_ATTR_MAX + 1];
|
||||
struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
|
||||
struct nlattr *mcgrp;
|
||||
int rem_mcgrp;
|
||||
|
||||
nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
|
||||
|
||||
if (!tb[CTRL_ATTR_MCAST_GROUPS]) {
|
||||
LOG(ERROR) << __func__ << "Multicast group not found";
|
||||
return -1;
|
||||
}
|
||||
|
||||
nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcgrp) {
|
||||
struct nlattr *tb_mcgrp[CTRL_ATTR_MCAST_GRP_MAX + 1];
|
||||
|
||||
nla_parse(tb_mcgrp, CTRL_ATTR_MCAST_GRP_MAX, reinterpret_cast<nlattr *>(nla_data(mcgrp)),
|
||||
nla_len(mcgrp), NULL);
|
||||
|
||||
if (!tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME] || !tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID])
|
||||
continue;
|
||||
|
||||
if (strncmp(reinterpret_cast<char *>(nla_data(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME])),
|
||||
grp->group, nla_len(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
|
||||
continue;
|
||||
|
||||
grp->id = nla_get_u32(tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nlGetMulticastId(struct nl_sock *sock, const char *family, const char *group) {
|
||||
int err = 0, ctrlid;
|
||||
struct HandlerArgs grp = {
|
||||
.group = group,
|
||||
.id = -ENOENT,
|
||||
};
|
||||
|
||||
std::unique_ptr<nl_msg, decltype(&nlmsg_free)> msg(nlmsg_alloc(), nlmsg_free);
|
||||
|
||||
ctrlid = genl_ctrl_resolve(sock, "nlctrl");
|
||||
|
||||
genlmsg_put(msg.get(), 0, 0, ctrlid, 0, 0, CTRL_CMD_GETFAMILY, 0);
|
||||
|
||||
nla_put_string(msg.get(), CTRL_ATTR_FAMILY_NAME, family);
|
||||
|
||||
err = nlSendMsg(sock, msg.get(), nlFamilyHandle, &grp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = grp.id;
|
||||
LOG(INFO) << group << " multicast_id: " << grp.id;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static bool socketAddMembership(struct nl_sock *sock, const char *group) {
|
||||
int mcid = nlGetMulticastId(sock, THERMAL_GENL_FAMILY_NAME, group);
|
||||
if (mcid < 0) {
|
||||
LOG(ERROR) << "Failed to get multicast id: " << group;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nl_socket_add_membership(sock, mcid)) {
|
||||
LOG(ERROR) << "Failed to add netlink socket membership: " << group;
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG(INFO) << "Added netlink socket membership: " << group;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int handleEvent(struct nl_msg *n, void *arg) {
|
||||
struct nlmsghdr *nlh = nlmsg_hdr(n);
|
||||
struct genlmsghdr *glh = genlmsg_hdr(nlh);
|
||||
struct nlattr *attrs[THERMAL_GENL_ATTR_MAX + 1];
|
||||
int *tz_id = reinterpret_cast<int *>(arg);
|
||||
|
||||
genlmsg_parse(nlh, 0, attrs, THERMAL_GENL_ATTR_MAX, NULL);
|
||||
|
||||
if (glh->cmd == THERMAL_GENL_EVENT_TZ_TRIP_UP) {
|
||||
LOG(INFO) << "THERMAL_GENL_EVENT_TZ_TRIP_UP";
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_ID]) {
|
||||
LOG(INFO) << "Thermal zone id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
|
||||
*tz_id = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
|
||||
}
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID])
|
||||
LOG(INFO) << "Thermal zone trip id: "
|
||||
<< nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]);
|
||||
}
|
||||
|
||||
if (glh->cmd == THERMAL_GENL_EVENT_TZ_TRIP_DOWN) {
|
||||
LOG(INFO) << "THERMAL_GENL_EVENT_TZ_TRIP_DOWN";
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_ID]) {
|
||||
LOG(INFO) << "Thermal zone id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
|
||||
*tz_id = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
|
||||
}
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID])
|
||||
LOG(INFO) << "Thermal zone trip id: "
|
||||
<< nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]);
|
||||
}
|
||||
|
||||
if (glh->cmd == THERMAL_GENL_EVENT_TZ_GOV_CHANGE) {
|
||||
LOG(INFO) << "THERMAL_GENL_EVENT_TZ_GOV_CHANGE";
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_ID]) {
|
||||
LOG(INFO) << "Thermal zone id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
|
||||
*tz_id = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
|
||||
}
|
||||
if (attrs[THERMAL_GENL_ATTR_GOV_NAME])
|
||||
LOG(INFO) << "Governor name: " << nla_get_string(attrs[THERMAL_GENL_ATTR_GOV_NAME]);
|
||||
}
|
||||
|
||||
if (glh->cmd == THERMAL_GENL_EVENT_TZ_CREATE) {
|
||||
LOG(INFO) << "THERMAL_GENL_EVENT_TZ_CREATE";
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_ID]) {
|
||||
LOG(INFO) << "Thermal zone id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
|
||||
*tz_id = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
|
||||
}
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_NAME])
|
||||
LOG(INFO) << "Thermal zone name: " << nla_get_string(attrs[THERMAL_GENL_ATTR_TZ_NAME]);
|
||||
}
|
||||
|
||||
if (glh->cmd == THERMAL_GENL_EVENT_TZ_DELETE) {
|
||||
LOG(INFO) << "THERMAL_GENL_EVENT_TZ_DELETE";
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_ID]) {
|
||||
LOG(INFO) << "Thermal zone id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
|
||||
*tz_id = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
|
||||
}
|
||||
}
|
||||
|
||||
if (glh->cmd == THERMAL_GENL_EVENT_TZ_DISABLE) {
|
||||
LOG(INFO) << "THERMAL_GENL_EVENT_TZ_DISABLE";
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_ID]) {
|
||||
LOG(INFO) << "Thermal zone id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
|
||||
*tz_id = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
|
||||
}
|
||||
}
|
||||
|
||||
if (glh->cmd == THERMAL_GENL_EVENT_TZ_ENABLE) {
|
||||
LOG(INFO) << "THERMAL_GENL_EVENT_TZ_ENABLE";
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_ID]) {
|
||||
LOG(INFO) << "Thermal zone id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
|
||||
*tz_id = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
|
||||
}
|
||||
}
|
||||
|
||||
if (glh->cmd == THERMAL_GENL_EVENT_TZ_TRIP_CHANGE) {
|
||||
LOG(INFO) << "THERMAL_GENL_EVENT_TZ_TRIP_CHANGE";
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_ID]) {
|
||||
LOG(INFO) << "Thermal zone id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
|
||||
*tz_id = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
|
||||
}
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID])
|
||||
LOG(INFO) << "Trip id:: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]);
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_TYPE])
|
||||
LOG(INFO) << "Trip type: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_TYPE]);
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_TEMP])
|
||||
LOG(INFO) << "Trip temp: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_TEMP]);
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_HYST])
|
||||
LOG(INFO) << "Trip hyst: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_HYST]);
|
||||
}
|
||||
|
||||
if (glh->cmd == THERMAL_GENL_EVENT_TZ_TRIP_ADD) {
|
||||
LOG(INFO) << "THERMAL_GENL_EVENT_TZ_TRIP_ADD";
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_ID])
|
||||
LOG(INFO) << "Thermal zone id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID])
|
||||
LOG(INFO) << "Trip id:: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]);
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_TYPE])
|
||||
LOG(INFO) << "Trip type: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_TYPE]);
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_TEMP])
|
||||
LOG(INFO) << "Trip temp: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_TEMP]);
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_HYST])
|
||||
LOG(INFO) << "Trip hyst: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_HYST]);
|
||||
}
|
||||
|
||||
if (glh->cmd == THERMAL_GENL_EVENT_TZ_TRIP_DELETE) {
|
||||
LOG(INFO) << "THERMAL_GENL_EVENT_TZ_TRIP_DELETE";
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_ID]) {
|
||||
LOG(INFO) << "Thermal zone id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
|
||||
*tz_id = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
|
||||
}
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID])
|
||||
LOG(INFO) << "Trip id:: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]);
|
||||
}
|
||||
|
||||
if (glh->cmd == THERMAL_GENL_EVENT_CDEV_STATE_UPDATE) {
|
||||
LOG(INFO) << "THERMAL_GENL_EVENT_CDEV_STATE_UPDATE";
|
||||
if (attrs[THERMAL_GENL_ATTR_CDEV_ID])
|
||||
LOG(INFO) << "Cooling device id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_ID]);
|
||||
if (attrs[THERMAL_GENL_ATTR_CDEV_CUR_STATE])
|
||||
LOG(INFO) << "Cooling device current state: "
|
||||
<< nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_CUR_STATE]);
|
||||
}
|
||||
|
||||
if (glh->cmd == THERMAL_GENL_EVENT_CDEV_ADD) {
|
||||
LOG(INFO) << "THERMAL_GENL_EVENT_CDEV_ADD";
|
||||
if (attrs[THERMAL_GENL_ATTR_CDEV_NAME])
|
||||
LOG(INFO) << "Cooling device name: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_NAME]);
|
||||
if (attrs[THERMAL_GENL_ATTR_CDEV_ID])
|
||||
LOG(INFO) << "Cooling device id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_ID]);
|
||||
if (attrs[THERMAL_GENL_ATTR_CDEV_MAX_STATE])
|
||||
LOG(INFO) << "Cooling device max state: "
|
||||
<< nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_MAX_STATE]);
|
||||
}
|
||||
|
||||
if (glh->cmd == THERMAL_GENL_EVENT_CDEV_DELETE) {
|
||||
LOG(INFO) << "THERMAL_GENL_EVENT_CDEV_DELETE";
|
||||
if (attrs[THERMAL_GENL_ATTR_CDEV_ID])
|
||||
LOG(INFO) << "Cooling device id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_ID]);
|
||||
}
|
||||
|
||||
if (glh->cmd == THERMAL_GENL_SAMPLING_TEMP) {
|
||||
LOG(INFO) << "THERMAL_GENL_SAMPLING_TEMP";
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_ID]) {
|
||||
LOG(INFO) << "Thermal zone id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
|
||||
*tz_id = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
|
||||
}
|
||||
if (attrs[THERMAL_GENL_ATTR_TZ_TEMP])
|
||||
LOG(INFO) << "Thermal zone temp: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TEMP]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ThermalWatcher::registerFilesToWatch(const std::set<std::string> &sensors_to_watch) {
|
||||
LOG(INFO) << "Uevent register file to watch...";
|
||||
monitored_sensors_.insert(sensors_to_watch.begin(), sensors_to_watch.end());
|
||||
|
||||
uevent_fd_.reset((TEMP_FAILURE_RETRY(uevent_open_socket(64 * 1024, true))));
|
||||
if (uevent_fd_.get() < 0) {
|
||||
LOG(ERROR) << "failed to open uevent socket";
|
||||
return;
|
||||
}
|
||||
|
||||
fcntl(uevent_fd_, F_SETFL, O_NONBLOCK);
|
||||
|
||||
looper_->addFd(uevent_fd_.get(), 0, ::android::Looper::EVENT_INPUT, nullptr, nullptr);
|
||||
sleep_ms_ = std::chrono::milliseconds(0);
|
||||
last_update_time_ = boot_clock::now();
|
||||
}
|
||||
|
||||
void ThermalWatcher::registerFilesToWatchNl(const std::set<std::string> &sensors_to_watch) {
|
||||
LOG(INFO) << "Thermal genl register file to watch...";
|
||||
monitored_sensors_.insert(sensors_to_watch.begin(), sensors_to_watch.end());
|
||||
|
||||
sk_thermal = nl_socket_alloc();
|
||||
if (!sk_thermal) {
|
||||
LOG(ERROR) << "nl_socket_alloc failed";
|
||||
return;
|
||||
}
|
||||
|
||||
if (genl_connect(sk_thermal)) {
|
||||
LOG(ERROR) << "genl_connect failed: sk_thermal";
|
||||
return;
|
||||
}
|
||||
|
||||
thermal_genl_fd_.reset(nl_socket_get_fd(sk_thermal));
|
||||
if (thermal_genl_fd_.get() < 0) {
|
||||
LOG(ERROR) << "Failed to create thermal netlink socket";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!socketAddMembership(sk_thermal, THERMAL_GENL_EVENT_GROUP_NAME)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently, only the update_temperature() will send thermal genl samlping events
|
||||
* from kernel. To avoid thermal-hal busy because samlping events are sent
|
||||
* too frequently, ignore thermal genl samlping events until we figure out how to use it.
|
||||
*
|
||||
if (!socketAddMembership(sk_thermal, THERMAL_GENL_SAMPLING_GROUP_NAME)) {
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
fcntl(thermal_genl_fd_, F_SETFL, O_NONBLOCK);
|
||||
looper_->addFd(thermal_genl_fd_.get(), 0, ::android::Looper::EVENT_INPUT, nullptr, nullptr);
|
||||
sleep_ms_ = std::chrono::milliseconds(0);
|
||||
last_update_time_ = boot_clock::now();
|
||||
}
|
||||
|
||||
bool ThermalWatcher::startWatchingDeviceFiles() {
|
||||
if (cb_) {
|
||||
auto ret = this->run("FileWatcherThread", ::android::PRIORITY_HIGHEST);
|
||||
if (ret != ::android::NO_ERROR) {
|
||||
LOG(ERROR) << "ThermalWatcherThread start fail";
|
||||
return false;
|
||||
} else {
|
||||
LOG(INFO) << "ThermalWatcherThread started";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void ThermalWatcher::parseUevent(std::set<std::string> *sensors_set) {
|
||||
bool thermal_event = false;
|
||||
constexpr int kUeventMsgLen = 2048;
|
||||
char msg[kUeventMsgLen + 2];
|
||||
char *cp;
|
||||
|
||||
while (true) {
|
||||
int n = uevent_kernel_multicast_recv(uevent_fd_.get(), msg, kUeventMsgLen);
|
||||
if (n <= 0) {
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||
LOG(ERROR) << "Error reading from Uevent Fd";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (n >= kUeventMsgLen) {
|
||||
LOG(ERROR) << "Uevent overflowed buffer, discarding";
|
||||
continue;
|
||||
}
|
||||
|
||||
msg[n] = '\0';
|
||||
msg[n + 1] = '\0';
|
||||
|
||||
cp = msg;
|
||||
while (*cp) {
|
||||
std::string uevent = cp;
|
||||
auto findSubSystemThermal = uevent.find("SUBSYSTEM=thermal");
|
||||
if (!thermal_event) {
|
||||
if (::android::base::StartsWith(uevent, "SUBSYSTEM=")) {
|
||||
if (findSubSystemThermal != std::string::npos) {
|
||||
thermal_event = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto start_pos = uevent.find("NAME=");
|
||||
if (start_pos != std::string::npos) {
|
||||
start_pos += 5;
|
||||
std::string name = uevent.substr(start_pos);
|
||||
if (monitored_sensors_.find(name) != monitored_sensors_.end()) {
|
||||
sensors_set->insert(name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (*cp++) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(b/175367921): Consider for potentially adding more type of event in the function
|
||||
// instead of just add the sensors to the list.
|
||||
void ThermalWatcher::parseGenlink(std::set<std::string> *sensors_set) {
|
||||
int err = 0, done = 0, tz_id = -1;
|
||||
|
||||
std::unique_ptr<nl_cb, decltype(&nl_cb_put)> cb(nl_cb_alloc(NL_CB_DEFAULT), nl_cb_put);
|
||||
|
||||
nl_cb_err(cb.get(), NL_CB_CUSTOM, nlErrorHandle, &err);
|
||||
nl_cb_set(cb.get(), NL_CB_FINISH, NL_CB_CUSTOM, nlFinishHandle, &done);
|
||||
nl_cb_set(cb.get(), NL_CB_ACK, NL_CB_CUSTOM, nlAckHandle, &done);
|
||||
nl_cb_set(cb.get(), NL_CB_SEQ_CHECK, NL_CB_CUSTOM, nlSeqCheckHandle, &done);
|
||||
nl_cb_set(cb.get(), NL_CB_VALID, NL_CB_CUSTOM, handleEvent, &tz_id);
|
||||
|
||||
while (!done && !err) {
|
||||
nl_recvmsgs(sk_thermal, cb.get());
|
||||
|
||||
if (tz_id < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
std::string name;
|
||||
if (getThermalZoneTypeById(tz_id, &name) &&
|
||||
monitored_sensors_.find(name) != monitored_sensors_.end()) {
|
||||
sensors_set->insert(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ThermalWatcher::wake() {
|
||||
looper_->wake();
|
||||
}
|
||||
|
||||
bool ThermalWatcher::threadLoop() {
|
||||
LOG(VERBOSE) << "ThermalWatcher polling...";
|
||||
|
||||
int fd;
|
||||
std::set<std::string> sensors;
|
||||
|
||||
auto time_elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(boot_clock::now() -
|
||||
last_update_time_);
|
||||
|
||||
if (time_elapsed_ms < sleep_ms_ &&
|
||||
looper_->pollOnce(sleep_ms_.count(), &fd, nullptr, nullptr) >= 0) {
|
||||
ATRACE_NAME("ThermalWatcher::threadLoop - receive event");
|
||||
if (fd != uevent_fd_.get() && fd != thermal_genl_fd_.get()) {
|
||||
return true;
|
||||
} else if (fd == thermal_genl_fd_.get()) {
|
||||
parseGenlink(&sensors);
|
||||
} else if (fd == uevent_fd_.get()) {
|
||||
parseUevent(&sensors);
|
||||
}
|
||||
// Ignore cb_ if uevent is not from monitored sensors
|
||||
if (sensors.size() == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
sleep_ms_ = cb_(sensors);
|
||||
last_update_time_ = boot_clock::now();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace thermal
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <android-base/chrono_utils.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <linux/genetlink.h>
|
||||
#include <netlink/genl/ctrl.h>
|
||||
#include <netlink/genl/genl.h>
|
||||
#include <utils/Looper.h>
|
||||
#include <utils/Thread.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <future>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace thermal {
|
||||
namespace implementation {
|
||||
|
||||
using ::android::base::boot_clock;
|
||||
using ::android::base::unique_fd;
|
||||
using WatcherCallback = std::function<std::chrono::milliseconds(const std::set<std::string> &name)>;
|
||||
|
||||
// A helper class for monitoring thermal files changes.
|
||||
class ThermalWatcher : public ::android::Thread {
|
||||
public:
|
||||
explicit ThermalWatcher(const WatcherCallback &cb)
|
||||
: Thread(false), cb_(cb), looper_(new ::android::Looper(true)) {}
|
||||
~ThermalWatcher() = default;
|
||||
|
||||
// Disallow copy and assign.
|
||||
ThermalWatcher(const ThermalWatcher &) = delete;
|
||||
void operator=(const ThermalWatcher &) = delete;
|
||||
|
||||
// Start the thread and return true if it succeeds.
|
||||
bool startWatchingDeviceFiles();
|
||||
// Give the file watcher a list of files to start watching. This helper
|
||||
// class will by default wait for modifications to the file with a looper.
|
||||
// This should be called before starting watcher thread.
|
||||
// For monitoring uevents.
|
||||
void registerFilesToWatch(const std::set<std::string> &sensors_to_watch);
|
||||
// For monitoring thermal genl events.
|
||||
void registerFilesToWatchNl(const std::set<std::string> &sensors_to_watch);
|
||||
// Wake up the looper thus the worker thread, immediately. This can be called
|
||||
// in any thread.
|
||||
void wake();
|
||||
|
||||
private:
|
||||
// The work done by the watcher thread. This will use inotify to check for
|
||||
// modifications to the files to watch. If any modification is seen this
|
||||
// will callback the registered function with the new data read from the
|
||||
// modified file.
|
||||
bool threadLoop() override;
|
||||
|
||||
// Parse uevent message
|
||||
void parseUevent(std::set<std::string> *sensor_name);
|
||||
|
||||
// Parse thermal netlink message
|
||||
void parseGenlink(std::set<std::string> *sensor_name);
|
||||
|
||||
// Maps watcher filer descriptor to watched file path.
|
||||
std::unordered_map<int, std::string> watch_to_file_path_map_;
|
||||
|
||||
// The callback function. Called whenever thermal uevent is seen.
|
||||
// The function passed in should expect a string in the form (type).
|
||||
// Where type is the name of the thermal zone that trigger a uevent notification.
|
||||
// Callback will return thermal trigger status for next polling decision.
|
||||
const WatcherCallback cb_;
|
||||
|
||||
::android::sp<::android::Looper> looper_;
|
||||
|
||||
// For uevent socket registration.
|
||||
::android::base::unique_fd uevent_fd_;
|
||||
// For thermal genl socket registration.
|
||||
::android::base::unique_fd thermal_genl_fd_;
|
||||
// Sensor list which monitor flag is enabled.
|
||||
std::set<std::string> monitored_sensors_;
|
||||
// Sleep interval voting result
|
||||
std::chrono::milliseconds sleep_ms_;
|
||||
// Timestamp for last thermal update
|
||||
boot_clock::time_point last_update_time_;
|
||||
// For thermal genl socket object.
|
||||
struct nl_sock *sk_thermal;
|
||||
};
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace thermal
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
@@ -26,10 +26,10 @@ cc_binary {
|
||||
"Usb.cpp",
|
||||
],
|
||||
shared_libs: [
|
||||
"android.hardware.usb-V1-ndk",
|
||||
"android.hardware.usb-V3-ndk",
|
||||
"libbase",
|
||||
"libbinder_ndk",
|
||||
"libcutils",
|
||||
"libcutils",
|
||||
"liblog",
|
||||
"libutils",
|
||||
],
|
||||
|
||||
@@ -173,6 +173,15 @@ Status queryMoistureDetectionStatus(std::vector<PortStatus> *currentPortStatus)
|
||||
return Status::SUCCESS;
|
||||
}
|
||||
|
||||
Status queryNonCompliantChargerStatus(std::vector<PortStatus> *currentPortStatus) {
|
||||
string reasons, path;
|
||||
|
||||
for (int i = 0; i < currentPortStatus->size(); i++) {
|
||||
(*currentPortStatus)[i].supportsComplianceWarnings = false;
|
||||
}
|
||||
return Status::SUCCESS;
|
||||
}
|
||||
|
||||
string appendRoleNodeHelper(const string &portName, PortRole::Tag tag) {
|
||||
string node(kTypecPath + portName);
|
||||
|
||||
@@ -568,12 +577,11 @@ Status getPortStatusHelper(std::vector<PortStatus> *currentPortStatus) {
|
||||
}
|
||||
|
||||
ALOGI("%d:%s connected:%d canChangeMode:%d canChagedata:%d canChangePower:%d "
|
||||
"usbDataEnabled:%d",
|
||||
i, port.first.c_str(), port.second,
|
||||
(*currentPortStatus)[i].canChangeMode,
|
||||
(*currentPortStatus)[i].canChangeDataRole,
|
||||
(*currentPortStatus)[i].canChangePowerRole,
|
||||
dataEnabled ? 1 : 0);
|
||||
"usbDataEnabled:%d plugOrientation:%d",
|
||||
i, port.first.c_str(), port.second, (*currentPortStatus)[i].canChangeMode,
|
||||
(*currentPortStatus)[i].canChangeDataRole,
|
||||
(*currentPortStatus)[i].canChangePowerRole, dataEnabled ? 1 : 0,
|
||||
(*currentPortStatus)[i].plugOrientation);
|
||||
}
|
||||
|
||||
return Status::SUCCESS;
|
||||
@@ -588,6 +596,7 @@ void queryVersionHelper(android::hardware::usb::Usb *usb,
|
||||
pthread_mutex_lock(&usb->mLock);
|
||||
status = getPortStatusHelper(currentPortStatus);
|
||||
queryMoistureDetectionStatus(currentPortStatus);
|
||||
queryNonCompliantChargerStatus(currentPortStatus);
|
||||
if (usb->mCallback != NULL) {
|
||||
ScopedAStatus ret = usb->mCallback->notifyPortStatusChange(*currentPortStatus,
|
||||
status);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<manifest version="1.0" type="device">
|
||||
<hal format="aidl">
|
||||
<name>android.hardware.usb</name>
|
||||
<version>1</version>
|
||||
<version>3</version>
|
||||
<interface>
|
||||
<name>IUsb</name>
|
||||
<instance>default</instance>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<manifest version="1.0" type="device">
|
||||
<hal format="aidl">
|
||||
<name>android.hardware.vibrator</name>
|
||||
<version>2</version>
|
||||
<fqname>IVibrator/default</fqname>
|
||||
</hal>
|
||||
</manifest>
|
||||
|
||||
Reference in New Issue
Block a user