8 Commits
vic ... udc

Author SHA1 Message Date
Tim Zimmermann
877c1a0564 aidl: Update light to V2
Change-Id: I126448662234741a158f41ebdc1577e9c3a44816
2024-08-04 10:57:32 +02:00
Tim Zimmermann
201fd3cc32 aidl: Remove thermal HAL
* Pixel thermal HAL can now be used directly

Change-Id: Ied8350355b819453e84026585f47e097d3f502f5
2024-08-04 10:51:55 +02:00
Tim Zimmermann
56626e0201 aidl: sensors: Use multihal sources directly from hardware/interfaces
* Possible after 5a856698db

Change-Id: I7b4beaf08327431740ab24dd651bc133bdf65cf1
2024-08-04 10:24:53 +02:00
matthuang
edb30cd0c5 Add group 'uhid' to AIDL sensors multi-HAL
Allow sensor hal to send SW_LID event through HID transport
drivers when hall_effect event is detected.

Bug: 262056923
Test: Build pass.
Change-Id: I9b583df6090a5e415abac7bef4bc3b7d28c31b8f
2024-08-03 21:55:10 +02:00
Roy Luo
a65af94562 Usb compliance warning extension
Add new warnings to enum ComplianceWarning

Test: atest VtsAidlUsbTargetTest
Bug: 296119135
Bug: 300340959
Change-Id: I5dcfe50285589d35dd2a2ab87020de8e2b92c181
2024-08-03 21:53:25 +02:00
RD Babiera
dd3baf47d3 Usb DisplayPort alt mode aidl interfaces
Adds enums for DisplayPortAltModeStatus and DisplayPortAltModePinAssignment.
Adds AltModeData and DisplayPortAltModeData.
Updates PortStatus to reflect these new enums and parcelables.

Test: atest VtsAidlUsbTargetTest
Bug: 253534975
Change-Id: I0fc62601dfc162b909e796586110686beed137ea
2024-08-03 21:51:21 +02:00
RD Babiera
4d5a25b7c1 Usb non-compliant port partner aidl extension
Adds aidl api definitions for notifying if the plugged Type-C
port partner (power source/accessory/cable) is non-compliant
with type-c power delivery specification. PortStatus is extended to have
a boolean that states whether or not this feature is supported as well
as an array for a new enum ComplianceWarning.

Test: atest VtsAidlUsbTargetTest
new test nonCompliantChargerStatus expects expects array to be empty
when the feature is not supported. new test nonCompliantChargerValues
expects any values in array to be in range of ComplianceWarning enums
if feature is supported.

Bug: 236322506
Change-Id: Ie3c2365e7c713327b44421c4d132b321d0e03d5f
2024-08-03 21:48:06 +02:00
Tim Zimmermann
bf39dfb28b aidl: Add missing vintf version entries
* This is required for devices using a target-level that actually
  has these HALs in their compatibility matrix

Change-Id: I29cba455ab92e7708ece405bb29ea1c46e46cf41
2024-08-03 21:44:08 +02:00
47 changed files with 115 additions and 7441 deletions

View File

@@ -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>

View File

@@ -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>

View File

@@ -17,7 +17,7 @@ cc_binary {
shared_libs: [
"libbase",
"libbinder_ndk",
"android.hardware.light-V1-ndk",
"android.hardware.light-V2-ndk",
],
vendor: true,
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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",
],
}

View File

@@ -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

View File

@@ -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

View 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

View 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

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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",
],
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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":"^(.+)$"
}
}
}
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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",
],

View File

@@ -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);

View File

@@ -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>

View File

@@ -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>