/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @addtogroup Thermal
 * @{
 */

/**
 * @file thermal.h
 */

#ifndef _ANDROID_THERMAL_H
#define _ANDROID_THERMAL_H

#include <sys/cdefs.h>

/******************************************************************
 *
 * IMPORTANT NOTICE:
 *
 *   This file is part of Android's set of stable system headers
 *   exposed by the Android NDK (Native Development Kit).
 *
 *   Third-party source AND binary code relies on the definitions
 *   here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
 *
 *   - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
 *   - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
 *   - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
 *   - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
 */

/*
 * Structures and functions to access thermal status and register/unregister
 * thermal status listener in native code.
 */

#include <stdint.h>
#include <sys/types.h>

#if !defined(__INTRODUCED_IN)
#define __INTRODUCED_IN(__api_level) /* nothing */
#endif

#ifdef __cplusplus
extern "C" {
#endif

/**
 * Thermal status used in function {@link AThermal_getCurrentThermalStatus} and
 * {@link AThermal_StatusCallback}.
 */
enum AThermalStatus {
    /** Error in thermal status. */
    ATHERMAL_STATUS_ERROR = -1,
    /** Not under throttling. */
    ATHERMAL_STATUS_NONE = 0,
    /** Light throttling where UX is not impacted. */
    ATHERMAL_STATUS_LIGHT = 1,
    /** Moderate throttling where UX is not largely impacted. */
    ATHERMAL_STATUS_MODERATE = 2,
    /** Severe throttling where UX is largely impacted. */
    ATHERMAL_STATUS_SEVERE = 3,
    /** Platform has done everything to reduce power. */
    ATHERMAL_STATUS_CRITICAL = 4,
    /**
     * Key components in platform are shutting down due to thermal condition.
     * Device functionalities will be limited.
     */
    ATHERMAL_STATUS_EMERGENCY = 5,
    /** Need shutdown immediately. */
    ATHERMAL_STATUS_SHUTDOWN = 6,
};
typedef enum AThermalStatus AThermalStatus;

/**
 * An opaque type representing a handle to a thermal manager.
 * An instance of thermal manager must be acquired prior to
 * using thermal status APIs and must be released after use.
 *
 * <p>To use:<ul>
 *    <li>Create a new thermal manager instance by calling the
 *        {@link AThermal_acquireManager} function.</li>
 *    <li>Get current thermal status with
 *        {@link AThermal_getCurrentThermalStatus}.</li>
 *    <li>Register a thermal status listener with
 *        {@link AThermal_registerThermalStatusListener}.</li>
 *    <li>Unregister a thermal status listener with
 *        {@link AThermal_unregisterThermalStatusListener}.</li>
 *    <li>Release the thermal manager instance with
 *        {@link AThermal_releaseManager}.</li></ul></p>
 *
 */
typedef struct AThermalManager AThermalManager;

/**
 * Prototype of the function that is called when thermal status changes.
 * It's passed the updated thermal status as parameter, as well as the
 * pointer provided by the client that registered a callback.
 */
typedef void (*AThermal_StatusCallback)(void* _Nullable data, AThermalStatus status);

/**
  * Acquire an instance of the thermal manager. This must be freed using
  * {@link AThermal_releaseManager}.
  *
  * Available since API level 30.
  *
  * @return manager instance on success, nullptr on failure.
  */
AThermalManager* _Nonnull AThermal_acquireManager() __INTRODUCED_IN(30);

/**
 * Release the thermal manager pointer acquired via
 * {@link AThermal_acquireManager}.
 *
 * Available since API level 30.
 *
 * @param manager The manager to be released.
 */
void AThermal_releaseManager(AThermalManager* _Nonnull manager) __INTRODUCED_IN(30);

/**
  * Gets the current thermal status.
  *
  * Available since API level 30.
  *
  * @param manager The manager instance to use to query the thermal status.
  *                Acquired via {@link AThermal_acquireManager}.
  *
  * @return current thermal status, ATHERMAL_STATUS_ERROR on failure.
  */
AThermalStatus
AThermal_getCurrentThermalStatus(AThermalManager *_Nonnull manager) __INTRODUCED_IN(30);

/**
 * Register a thermal status listener for thermal status change.
 *
 * Available since API level 30.
 *
 * @param manager The manager instance to use to register.
 *                Acquired via {@link AThermal_acquireManager}.
 * @param callback The callback function to be called on system binder thread pool when thermal
 *                 status updated.
 * @param data The data pointer to be passed when callback is called.
 *
 * @return 0 on success
 *         EINVAL if the listener and data pointer were previously added and not removed.
 *         EPIPE if communication with the system service has failed, the listener will not get
 *               removed and this call should be retried
 */
int AThermal_registerThermalStatusListener(AThermalManager *_Nonnull manager,
                                           AThermal_StatusCallback _Nullable callback,
                                           void* _Nullable data) __INTRODUCED_IN(30);

/**
 * Unregister a thermal status listener previously registered.
 *
 * No subsequent invocations of the callback will occur after this function returns successfully.
 *
 * Available since API level 30.
 *
 * @param manager The manager instance to use to unregister.
 *                Acquired via {@link AThermal_acquireManager}.
 * @param callback The callback function that was previously registered.
 * @param data The data pointer to be passed when callback is called.
 *
 * @return 0 on success
 *         EINVAL if the listener and data pointer were not previously added.
 *         EPIPE if communication with the system service has failed.
 */
int AThermal_unregisterThermalStatusListener(AThermalManager* _Nonnull manager,
                                             AThermal_StatusCallback _Nullable callback,
                                             void* _Nullable data) __INTRODUCED_IN(30);

/**
 * Provides an estimate of how much thermal headroom the device currently has before
 * hitting severe throttling.
 *
 * Note that this only attempts to track the headroom of slow-moving sensors, such as
 * the skin temperature sensor. This means that there is no benefit to calling this function
 * more frequently than about once per second, and attempted to call significantly
 * more frequently may result in the function returning `NaN`.
 *
 * In addition, in order to be able to provide an accurate forecast, the system does
 * not attempt to forecast until it has multiple temperature samples from which to
 * extrapolate. This should only take a few seconds from the time of the first call,
 * but during this time, no forecasting will occur, and the current headroom will be
 * returned regardless of the value of `forecastSeconds`.
 *
 * The value returned is a non-negative float that represents how much of the thermal envelope
 * is in use (or is forecasted to be in use). A value of 1.0 indicates that the device is
 * (or will be) throttled at {@link #ATHERMAL_STATUS_SEVERE}. Such throttling can affect the
 * CPU, GPU, and other subsystems. Values may exceed 1.0, but there is no implied mapping
 * to specific thermal levels beyond that point. This means that values greater than 1.0
 * may correspond to {@link #ATHERMAL_STATUS_SEVERE}, but may also represent heavier throttling.
 *
 * A value of 0.0 corresponds to a fixed distance from 1.0, but does not correspond to any
 * particular thermal status or temperature. Values on (0.0, 1.0] may be expected to scale
 * linearly with temperature, though temperature changes over time are typically not linear.
 * Negative values will be clamped to 0.0 before returning.
 *
 * Available since API level 31.
 *
 * @param manager The manager instance to use.
 *                Acquired via {@link AThermal_acquireManager}.
 * @param forecastSeconds how many seconds into the future to forecast. Given that device
 *                        conditions may change at any time, forecasts from further in the
 *                        future will likely be less accurate than forecasts in the near future.
 * @return a value greater than equal to 0.0, where 1.0 indicates the SEVERE throttling threshold,
 *         as described above. Returns NaN if the device does not support this functionality or
 *         if this function is called significantly faster than once per second.
  */
float AThermal_getThermalHeadroom(AThermalManager* _Nonnull manager,
                                  int forecastSeconds) __INTRODUCED_IN(31);

/**
 * This struct defines an instance of headroom threshold value and its status.
 * <p>
 * The value should be monotonically non-decreasing as the thermal status increases.
 * For {@link ATHERMAL_STATUS_SEVERE}, its headroom threshold is guaranteed to
 * be 1.0f. For status below severe status, the value should be lower or equal
 * to 1.0f, and for status above severe, the value should be larger or equal to 1.0f.
 * <p>
 * Also see {@link AThermal_getThermalHeadroom} for explanation on headroom, and
 * {@link AThermal_getThermalHeadroomThresholds} for how to use this.
 */
struct AThermalHeadroomThreshold {
    float headroom;
    AThermalStatus thermalStatus;
};
typedef struct AThermalHeadroomThreshold AThermalHeadroomThreshold;

/**
 * Gets the thermal headroom thresholds for all available thermal status.
 *
 * A thermal status will only exist in output if the device manufacturer has the
 * corresponding threshold defined for at least one of its slow-moving skin temperature
 * sensors. If it's set, one should also expect to get it from
 * {@link #AThermal_getCurrentThermalStatus} or {@link AThermal_StatusCallback}.
 * <p>
 * The headroom threshold is used to interpret the possible thermal throttling status based on
 * the headroom prediction. For example, if the headroom threshold for
 * {@link ATHERMAL_STATUS_LIGHT} is 0.7, and a headroom prediction in 10s returns 0.75
 * (or `AThermal_getThermalHeadroom(10)=0.75}`, one can expect that in 10 seconds the system
 * could be in lightly throttled state if the workload remains the same. The app can consider
 * taking actions according to the nearest throttling status the difference between the headroom and
 * the threshold.
 * <p>
 * For new devices it's guaranteed to have a single sensor, but for older devices with multiple
 * sensors reporting different threshold values, the minimum threshold is taken to be conservative
 * on predictions. Thus, when reading real-time headroom, it's not guaranteed that a real-time value
 * of 0.75 (or `AThermal_getThermalHeadroom(0)=0.75`) exceeding the threshold of 0.7 above
 * will always come with lightly throttled state
 * (or `AThermal_getCurrentThermalStatus()=ATHERMAL_STATUS_LIGHT`) but it can be lower
 * (or `AThermal_getCurrentThermalStatus()=ATHERMAL_STATUS_NONE`).
 * While it's always guaranteed that the device won't be throttled heavier than the unmet
 * threshold's state, so a real-time headroom of 0.75 will never come with
 * {@link #ATHERMAL_STATUS_MODERATE} but always lower, and 0.65 will never come with
 * {@link ATHERMAL_STATUS_LIGHT} but {@link #ATHERMAL_STATUS_NONE}.
 * <p>
 * Starting in Android 16, this polling API may return different results when called depending on
 * the device. The new headroom listener API {@link #AThermal_HeadroomCallback} can be used to
 * detect headroom thresholds changes.
 * <p>
 * Before API level 36 the returned list of thresholds is cached on first successful query and owned
 * by the thermal manager, which will not change between calls to this function. The caller should
 * only need to free the manager with {@link AThermal_releaseManager}.
 * <p>
 *
 * @param manager The manager instance to use.
 *                Acquired via {@link AThermal_acquireManager}.
 * @param outThresholds non-null output pointer to null AThermalHeadroomThreshold pointer, which
 *                will be set to a new array of thresholds if thermal thresholds are supported
 *                by the system or device, otherwise nullptr or unmodified. The client should
 *                clean up the thresholds by array-deleting the threshold pointer.
 * @param size non-null output pointer whose value will be set to the size of the threshold array
 *             or 0 if it's not supported.
 * @return 0 on success
 *         EINVAL if outThresholds or size_t is nullptr, or *outThresholds is not nullptr.
 *         EPIPE if communication with the system service has failed.
 *         ENOSYS if the feature is disabled by the current system.
 */
int AThermal_getThermalHeadroomThresholds(AThermalManager* _Nonnull manager,
                                          const AThermalHeadroomThreshold* _Nonnull
                                          * _Nullable outThresholds,
                                          size_t* _Nonnull size) __INTRODUCED_IN(35);

/**
 * Prototype of the function that is called when thermal headroom or thresholds changes.
 * It's passed the updated thermal headroom and thresholds as parameters, as well as the
 * pointer provided by the client that registered a callback.
 * <p>
 * This may not be used to fully replace the {@link AThermal_getThermalHeadroom} API as it will
 * only notify on one of the conditions below that will significantly change one or both
 * values of current headroom and headroom thresholds since previous callback:
 *   1. thermal throttling events: when the skin temperature has cross any of the thresholds
 *      and there isn't a previous callback in a short time ago with similar values.
 *   2. skin temperature threshold change events: note that if the absolute °C threshold
 *      values change in a way that does not significantly change the current headroom nor
 *      headroom thresholds, it will not trigger any callback. The client should not
 *      need to take action in such case since the difference from temperature vs threshold
 *      hasn't changed.
 * <p>
 * By API version 36, it provides a forecast in the same call for developer's convenience
 * based on a {@code forecastSeconds} defined by the device, which can be static or dynamic
 * varied by OEM. Be aware that it will not notify on forecast temperature change but the
 * events mentioned above. So periodically polling against {@link AThermal_getThermalHeadroom}
 * API should still be used to actively monitor temperature forecast in advance.
 * <p>
 * This serves as a more advanced option compared to thermal status listener, where the
 * latter will only notify on thermal throttling events with status update.
 *
 * @param data The data pointer to be passed when callback is called.
 * @param headroom The current non-negative normalized headroom value, also see
 *                 {@link AThermal_getThermalHeadroom}.
 * @param forecastHeadroom The forecasted non-negative normalized headroom value, also see
 *                         {@link AThermal_getThermalHeadroom}.
 * @param forecastSeconds The seconds used for the forecast by the system.
 * @param thresholds The current headroom thresholds. The thresholds pointer will be a constant
 *                   shared across all callbacks registered from the same process, and it will be
 *                   destroyed after all the callbacks are finished. If the client intents to
 *                   persist the values, it should make a copy of it during the callback.
 * @param thresholdsCount The count of thresholds.
 */
typedef void (*AThermal_HeadroomCallback)(void *_Nullable data,
                                          float headroom,
                                          float forecastHeadroom,
                                          int forecastSeconds,
                                          const AThermalHeadroomThreshold* _Nullable thresholds,
                                          size_t thresholdsCount);

/**
 * Register a thermal headroom listener for thermal headroom or thresholds change.
 *
 * Available since API level 36.
 *
 * @param manager The manager instance to use to register.
 *                Acquired via {@link AThermal_acquireManager}.
 * @param callback The callback function to be called on system binder thread pool when thermal
 *                 headroom or thresholds update.
 * @param data The data pointer to be passed when callback is called.
 *
 * @return 0 on success
 *         EINVAL if the listener and data pointer were previously added and not removed.
 *         EPIPE if communication with the system service has failed.
 */
int AThermal_registerThermalHeadroomListener(AThermalManager* _Nonnull manager,
                                             AThermal_HeadroomCallback _Nullable callback,
                                             void* _Nullable data) __INTRODUCED_IN(36);

/**
 * Unregister a thermal headroom listener previously registered.
 *
 * No subsequent invocations of the callback will occur after this function returns successfully.
 *
 * Available since API level 36.
 *
 * @param manager The manager instance to use to unregister.
 *                Acquired via {@link AThermal_acquireManager}.
 * @param callback The callback function that was previously registered.
 * @param data The data pointer that was previously registered.
 *
 * @return 0 on success
 *         EINVAL if the listener and data pointer were not previously added.
 *         EPIPE if communication with the system service has failed, the listener will not get
 *               removed and this call should be retried
 */

int AThermal_unregisterThermalHeadroomListener(AThermalManager* _Nonnull manager,
                                               AThermal_HeadroomCallback _Nullable callback,
                                               void* _Nullable data) __INTRODUCED_IN(36);

#ifdef __cplusplus
}
#endif

#endif // _ANDROID_THERMAL_H

/** @} */
