Home | History | Annotate | Download | only in power
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.power;
     18 
     19 import android.annotation.Nullable;
     20 import android.content.Context;
     21 import android.hardware.thermal.V1_0.ThermalStatus;
     22 import android.hardware.thermal.V1_0.ThermalStatusCode;
     23 import android.hardware.thermal.V1_1.IThermalCallback;
     24 import android.hardware.thermal.V2_0.IThermalChangedCallback;
     25 import android.hardware.thermal.V2_0.ThrottlingSeverity;
     26 import android.os.Binder;
     27 import android.os.CoolingDevice;
     28 import android.os.HwBinder;
     29 import android.os.IThermalEventListener;
     30 import android.os.IThermalService;
     31 import android.os.IThermalStatusListener;
     32 import android.os.PowerManager;
     33 import android.os.Process;
     34 import android.os.RemoteCallbackList;
     35 import android.os.RemoteException;
     36 import android.os.ResultReceiver;
     37 import android.os.ShellCallback;
     38 import android.os.ShellCommand;
     39 import android.os.Temperature;
     40 import android.util.ArrayMap;
     41 import android.util.Slog;
     42 
     43 import com.android.internal.annotations.GuardedBy;
     44 import com.android.internal.annotations.VisibleForTesting;
     45 import com.android.internal.util.DumpUtils;
     46 import com.android.server.FgThread;
     47 import com.android.server.SystemService;
     48 
     49 import java.io.FileDescriptor;
     50 import java.io.PrintWriter;
     51 import java.util.ArrayList;
     52 import java.util.Collection;
     53 import java.util.Iterator;
     54 import java.util.List;
     55 import java.util.NoSuchElementException;
     56 import java.util.concurrent.atomic.AtomicBoolean;
     57 
     58 /**
     59  * This is a system service that listens to HAL thermal events and dispatch those to listeners.
     60  * <p>The service will also trigger actions based on severity of the throttling status.</p>
     61  *
     62  * @hide
     63  */
     64 public class ThermalManagerService extends SystemService {
     65     private static final String TAG = ThermalManagerService.class.getSimpleName();
     66 
     67     /** Lock to protect listen list. */
     68     private final Object mLock = new Object();
     69 
     70     /**
     71      * Registered observers of the thermal events. Cookie is used to store type as Integer, null
     72      * means no filter.
     73      */
     74     @GuardedBy("mLock")
     75     private final RemoteCallbackList<IThermalEventListener> mThermalEventListeners =
     76             new RemoteCallbackList<>();
     77 
     78     /** Registered observers of the thermal status. */
     79     @GuardedBy("mLock")
     80     private final RemoteCallbackList<IThermalStatusListener> mThermalStatusListeners =
     81             new RemoteCallbackList<>();
     82 
     83     /** Current thermal status */
     84     @GuardedBy("mLock")
     85     private int mStatus;
     86 
     87     /** If override status takes effect*/
     88     @GuardedBy("mLock")
     89     private boolean mIsStatusOverride;
     90 
     91     /** Current thermal map, key as name */
     92     @GuardedBy("mLock")
     93     private ArrayMap<String, Temperature> mTemperatureMap = new ArrayMap<>();
     94 
     95     /** HAL wrapper. */
     96     private ThermalHalWrapper mHalWrapper;
     97 
     98     /** Hal ready. */
     99     private final AtomicBoolean mHalReady = new AtomicBoolean();
    100 
    101     /** Invalid throttling status */
    102     private static final int INVALID_THROTTLING = Integer.MIN_VALUE;
    103 
    104     public ThermalManagerService(Context context) {
    105         this(context, null);
    106     }
    107 
    108     @VisibleForTesting
    109     ThermalManagerService(Context context, @Nullable ThermalHalWrapper halWrapper) {
    110         super(context);
    111         mHalWrapper = halWrapper;
    112         // Initialize to invalid to send status onActivityManagerReady
    113         mStatus = INVALID_THROTTLING;
    114     }
    115 
    116     @Override
    117     public void onStart() {
    118         publishBinderService(Context.THERMAL_SERVICE, mService);
    119     }
    120 
    121     @Override
    122     public void onBootPhase(int phase) {
    123         if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
    124             onActivityManagerReady();
    125         }
    126     }
    127 
    128     private void onActivityManagerReady() {
    129         synchronized (mLock) {
    130             // Connect to HAL and post to listeners.
    131             boolean halConnected = (mHalWrapper != null);
    132             if (!halConnected) {
    133                 mHalWrapper = new ThermalHal20Wrapper();
    134                 halConnected = mHalWrapper.connectToHal();
    135             }
    136             if (!halConnected) {
    137                 mHalWrapper = new ThermalHal11Wrapper();
    138                 halConnected = mHalWrapper.connectToHal();
    139             }
    140             if (!halConnected) {
    141                 mHalWrapper = new ThermalHal10Wrapper();
    142                 halConnected = mHalWrapper.connectToHal();
    143             }
    144             mHalWrapper.setCallback(this::onTemperatureChangedCallback);
    145             if (!halConnected) {
    146                 return;
    147             }
    148             List<Temperature> temperatures = mHalWrapper.getCurrentTemperatures(false,
    149                     0);
    150             final int count = temperatures.size();
    151             for (int i = 0; i < count; i++) {
    152                 onTemperatureChanged(temperatures.get(i), false);
    153             }
    154             onTemperatureMapChangedLocked();
    155             mHalReady.set(true);
    156         }
    157     }
    158 
    159     private void postStatusListener(IThermalStatusListener listener) {
    160         final boolean thermalCallbackQueued = FgThread.getHandler().post(() -> {
    161             try {
    162                 listener.onStatusChange(mStatus);
    163             } catch (RemoteException | RuntimeException e) {
    164                 Slog.e(TAG, "Thermal callback failed to call", e);
    165             }
    166         });
    167         if (!thermalCallbackQueued) {
    168             Slog.e(TAG, "Thermal callback failed to queue");
    169         }
    170     }
    171 
    172     private void notifyStatusListenersLocked() {
    173         if (!Temperature.isValidStatus(mStatus)) {
    174             return;
    175         }
    176         final int length = mThermalStatusListeners.beginBroadcast();
    177         try {
    178             for (int i = 0; i < length; i++) {
    179                 final IThermalStatusListener listener =
    180                         mThermalStatusListeners.getBroadcastItem(i);
    181                 postStatusListener(listener);
    182             }
    183         } finally {
    184             mThermalStatusListeners.finishBroadcast();
    185         }
    186     }
    187 
    188     private void onTemperatureMapChangedLocked() {
    189         int newStatus = INVALID_THROTTLING;
    190         final int count = mTemperatureMap.size();
    191         for (int i = 0; i < count; i++) {
    192             Temperature t = mTemperatureMap.valueAt(i);
    193             if (t.getStatus() >= newStatus) {
    194                 newStatus = t.getStatus();
    195             }
    196         }
    197         // Do not update if override from shell
    198         if (!mIsStatusOverride) {
    199             setStatusLocked(newStatus);
    200         }
    201     }
    202 
    203     private void setStatusLocked(int newStatus) {
    204         if (newStatus != mStatus) {
    205             mStatus = newStatus;
    206             notifyStatusListenersLocked();
    207         }
    208     }
    209 
    210     private void postEventListenerCurrentTemperatures(IThermalEventListener listener,
    211             @Nullable Integer type) {
    212         synchronized (mLock) {
    213             final int count = mTemperatureMap.size();
    214             for (int i = 0; i < count; i++) {
    215                 postEventListener(mTemperatureMap.valueAt(i), listener,
    216                         type);
    217             }
    218         }
    219     }
    220 
    221     private void postEventListener(Temperature temperature,
    222             IThermalEventListener listener,
    223             @Nullable Integer type) {
    224         // Skip if listener registered with a different type
    225         if (type != null && type != temperature.getType()) {
    226             return;
    227         }
    228         final boolean thermalCallbackQueued = FgThread.getHandler().post(() -> {
    229             try {
    230                 listener.notifyThrottling(temperature);
    231             } catch (RemoteException | RuntimeException e) {
    232                 Slog.e(TAG, "Thermal callback failed to call", e);
    233             }
    234         });
    235         if (!thermalCallbackQueued) {
    236             Slog.e(TAG, "Thermal callback failed to queue");
    237         }
    238     }
    239 
    240     private void notifyEventListenersLocked(Temperature temperature) {
    241         final int length = mThermalEventListeners.beginBroadcast();
    242         try {
    243             for (int i = 0; i < length; i++) {
    244                 final IThermalEventListener listener =
    245                         mThermalEventListeners.getBroadcastItem(i);
    246                 final Integer type =
    247                         (Integer) mThermalEventListeners.getBroadcastCookie(i);
    248                 postEventListener(temperature, listener, type);
    249             }
    250         } finally {
    251             mThermalEventListeners.finishBroadcast();
    252         }
    253     }
    254 
    255     private void shutdownIfNeeded(Temperature temperature) {
    256         if (temperature.getStatus() != Temperature.THROTTLING_SHUTDOWN) {
    257             return;
    258         }
    259         final PowerManager powerManager = getContext().getSystemService(PowerManager.class);
    260         switch (temperature.getType()) {
    261             case Temperature.TYPE_CPU:
    262                 // Fall through
    263             case Temperature.TYPE_GPU:
    264                 // Fall through
    265             case Temperature.TYPE_NPU:
    266                 // Fall through
    267             case Temperature.TYPE_SKIN:
    268                 powerManager.shutdown(false, PowerManager.SHUTDOWN_THERMAL_STATE, false);
    269                 break;
    270             case Temperature.TYPE_BATTERY:
    271                 powerManager.shutdown(false, PowerManager.SHUTDOWN_BATTERY_THERMAL_STATE, false);
    272                 break;
    273         }
    274     }
    275 
    276     private void onTemperatureChanged(Temperature temperature, boolean sendStatus) {
    277         shutdownIfNeeded(temperature);
    278         synchronized (mLock) {
    279             Temperature old = mTemperatureMap.put(temperature.getName(), temperature);
    280             if (old != null) {
    281                 if (old.getStatus() != temperature.getStatus()) {
    282                     notifyEventListenersLocked(temperature);
    283                 }
    284             } else {
    285                 notifyEventListenersLocked(temperature);
    286             }
    287             if (sendStatus) {
    288                 onTemperatureMapChangedLocked();
    289             }
    290         }
    291     }
    292 
    293     /* HwBinder callback **/
    294     private void onTemperatureChangedCallback(Temperature temperature) {
    295         final long token = Binder.clearCallingIdentity();
    296         try {
    297             onTemperatureChanged(temperature, true);
    298         } finally {
    299             Binder.restoreCallingIdentity(token);
    300         }
    301     }
    302 
    303     @VisibleForTesting
    304     final IThermalService.Stub mService = new IThermalService.Stub() {
    305         @Override
    306         public boolean registerThermalEventListener(IThermalEventListener listener) {
    307             getContext().enforceCallingOrSelfPermission(
    308                     android.Manifest.permission.DEVICE_POWER, null);
    309             synchronized (mLock) {
    310                 final long token = Binder.clearCallingIdentity();
    311                 try {
    312                     if (!mThermalEventListeners.register(listener, null)) {
    313                         return false;
    314                     }
    315                     // Notify its callback after new client registered.
    316                     postEventListenerCurrentTemperatures(listener, null);
    317                     return true;
    318                 } finally {
    319                     Binder.restoreCallingIdentity(token);
    320                 }
    321             }
    322         }
    323 
    324         @Override
    325         public boolean registerThermalEventListenerWithType(IThermalEventListener listener,
    326                 int type) {
    327             getContext().enforceCallingOrSelfPermission(
    328                     android.Manifest.permission.DEVICE_POWER, null);
    329             synchronized (mLock) {
    330                 final long token = Binder.clearCallingIdentity();
    331                 try {
    332                     if (!mThermalEventListeners.register(listener, new Integer(type))) {
    333                         return false;
    334                     }
    335                     // Notify its callback after new client registered.
    336                     postEventListenerCurrentTemperatures(listener, new Integer(type));
    337                     return true;
    338                 } finally {
    339                     Binder.restoreCallingIdentity(token);
    340                 }
    341             }
    342         }
    343 
    344         @Override
    345         public boolean unregisterThermalEventListener(IThermalEventListener listener) {
    346             getContext().enforceCallingOrSelfPermission(
    347                     android.Manifest.permission.DEVICE_POWER, null);
    348             synchronized (mLock) {
    349                 final long token = Binder.clearCallingIdentity();
    350                 try {
    351                     return mThermalEventListeners.unregister(listener);
    352                 } finally {
    353                     Binder.restoreCallingIdentity(token);
    354                 }
    355             }
    356         }
    357 
    358         @Override
    359         public List<Temperature> getCurrentTemperatures() {
    360             getContext().enforceCallingOrSelfPermission(
    361                     android.Manifest.permission.DEVICE_POWER, null);
    362             final long token = Binder.clearCallingIdentity();
    363             try {
    364                 if (!mHalReady.get()) {
    365                     return new ArrayList<>();
    366                 }
    367                 return mHalWrapper.getCurrentTemperatures(false, 0 /* not used */);
    368             } finally {
    369                 Binder.restoreCallingIdentity(token);
    370             }
    371         }
    372 
    373         @Override
    374         public List<Temperature> getCurrentTemperaturesWithType(int type) {
    375             getContext().enforceCallingOrSelfPermission(
    376                     android.Manifest.permission.DEVICE_POWER, null);
    377             final long token = Binder.clearCallingIdentity();
    378             try {
    379                 if (!mHalReady.get()) {
    380                     return new ArrayList<>();
    381                 }
    382                 return mHalWrapper.getCurrentTemperatures(true, type);
    383             } finally {
    384                 Binder.restoreCallingIdentity(token);
    385             }
    386         }
    387 
    388         @Override
    389         public boolean registerThermalStatusListener(IThermalStatusListener listener) {
    390             synchronized (mLock) {
    391                 // Notify its callback after new client registered.
    392                 final long token = Binder.clearCallingIdentity();
    393                 try {
    394                     if (!mThermalStatusListeners.register(listener)) {
    395                         return false;
    396                     }
    397                     // Notify its callback after new client registered.
    398                     postStatusListener(listener);
    399                     return true;
    400                 } finally {
    401                     Binder.restoreCallingIdentity(token);
    402                 }
    403             }
    404         }
    405 
    406         @Override
    407         public boolean unregisterThermalStatusListener(IThermalStatusListener listener) {
    408             synchronized (mLock) {
    409                 final long token = Binder.clearCallingIdentity();
    410                 try {
    411                     return mThermalStatusListeners.unregister(listener);
    412                 } finally {
    413                     Binder.restoreCallingIdentity(token);
    414                 }
    415             }
    416         }
    417 
    418         @Override
    419         public int getCurrentThermalStatus() {
    420             synchronized (mLock) {
    421                 final long token = Binder.clearCallingIdentity();
    422                 try {
    423                     return Temperature.isValidStatus(mStatus) ? mStatus
    424                             : Temperature.THROTTLING_NONE;
    425                 } finally {
    426                     Binder.restoreCallingIdentity(token);
    427                 }
    428             }
    429         }
    430 
    431         @Override
    432         public List<CoolingDevice> getCurrentCoolingDevices() {
    433             getContext().enforceCallingOrSelfPermission(
    434                     android.Manifest.permission.DEVICE_POWER, null);
    435             final long token = Binder.clearCallingIdentity();
    436             try {
    437                 if (!mHalReady.get()) {
    438                     return new ArrayList<>();
    439                 }
    440                 return mHalWrapper.getCurrentCoolingDevices(false, 0);
    441             } finally {
    442                 Binder.restoreCallingIdentity(token);
    443             }
    444         }
    445 
    446         @Override
    447         public List<CoolingDevice> getCurrentCoolingDevicesWithType(int type) {
    448             getContext().enforceCallingOrSelfPermission(
    449                     android.Manifest.permission.DEVICE_POWER, null);
    450             final long token = Binder.clearCallingIdentity();
    451             try {
    452                 if (!mHalReady.get()) {
    453                     return new ArrayList<>();
    454                 }
    455                 return mHalWrapper.getCurrentCoolingDevices(true, type);
    456             } finally {
    457                 Binder.restoreCallingIdentity(token);
    458             }
    459         }
    460 
    461         private void dumpItemsLocked(PrintWriter pw, String prefix,
    462                 Collection<?> items) {
    463             for (Iterator iterator = items.iterator(); iterator.hasNext();) {
    464                 pw.println(prefix + iterator.next().toString());
    465             }
    466         }
    467 
    468         @Override
    469         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    470             if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
    471                 return;
    472             }
    473             final long token = Binder.clearCallingIdentity();
    474             try {
    475                 synchronized (mLock) {
    476                     pw.println("IsStatusOverride: " + mIsStatusOverride);
    477                     pw.println("ThermalEventListeners:");
    478                     mThermalEventListeners.dump(pw, "\t");
    479                     pw.println("ThermalStatusListeners:");
    480                     mThermalStatusListeners.dump(pw, "\t");
    481                     pw.println("Thermal Status: " + mStatus);
    482                     pw.println("Cached temperatures:");
    483                     dumpItemsLocked(pw, "\t", mTemperatureMap.values());
    484                     pw.println("HAL Ready: " + mHalReady.get());
    485                     if (mHalReady.get()) {
    486                         pw.println("HAL connection:");
    487                         mHalWrapper.dump(pw, "\t");
    488                         pw.println("Current temperatures from HAL:");
    489                         dumpItemsLocked(pw, "\t",
    490                                 mHalWrapper.getCurrentTemperatures(false, 0));
    491                         pw.println("Current cooling devices from HAL:");
    492                         dumpItemsLocked(pw, "\t",
    493                                 mHalWrapper.getCurrentCoolingDevices(false, 0));
    494                     }
    495                 }
    496             } finally {
    497                 Binder.restoreCallingIdentity(token);
    498             }
    499         }
    500 
    501         private boolean isCallerShell() {
    502             final int callingUid = Binder.getCallingUid();
    503             return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
    504         }
    505 
    506         @Override
    507         public void onShellCommand(FileDescriptor in, FileDescriptor out,
    508                 FileDescriptor err, String[] args, ShellCallback callback,
    509                 ResultReceiver resultReceiver) {
    510             if (!isCallerShell()) {
    511                 Slog.w(TAG, "Only shell is allowed to call thermalservice shell commands");
    512                 return;
    513             }
    514             (new ThermalShellCommand()).exec(
    515                     this, in, out, err, args, callback, resultReceiver);
    516         }
    517 
    518     };
    519 
    520     class ThermalShellCommand extends ShellCommand {
    521         @Override
    522         public int onCommand(String cmd) {
    523             switch(cmd != null ? cmd : "") {
    524                 case "override-status":
    525                     return runOverrideStatus();
    526                 case "reset":
    527                     return runReset();
    528                 default:
    529                     return handleDefaultCommands(cmd);
    530             }
    531         }
    532 
    533         private int runReset() {
    534             final long token = Binder.clearCallingIdentity();
    535             try {
    536                 synchronized (mLock) {
    537                     mIsStatusOverride = false;
    538                     onTemperatureMapChangedLocked();
    539                     return 0;
    540                 }
    541             } finally {
    542                 Binder.restoreCallingIdentity(token);
    543             }
    544         }
    545 
    546         private int runOverrideStatus() {
    547             final long token = Binder.clearCallingIdentity();
    548             try {
    549                 final PrintWriter pw = getOutPrintWriter();
    550                 int status;
    551                 try {
    552                     status = Integer.parseInt(getNextArgRequired());
    553                 } catch (RuntimeException ex) {
    554                     pw.println("Error: " + ex.toString());
    555                     return -1;
    556                 }
    557                 if (!Temperature.isValidStatus(status)) {
    558                     pw.println("Invalid status: " + status);
    559                     return -1;
    560                 }
    561                 synchronized (mLock) {
    562                     mIsStatusOverride = true;
    563                     setStatusLocked(status);
    564                 }
    565                 return 0;
    566             } finally {
    567                 Binder.restoreCallingIdentity(token);
    568             }
    569         }
    570 
    571         @Override
    572         public void onHelp() {
    573             final PrintWriter pw = getOutPrintWriter();
    574             pw.println("Thermal service (thermalservice) commands:");
    575             pw.println("  help");
    576             pw.println("    Print this help text.");
    577             pw.println("");
    578             pw.println("  override-status STATUS");
    579             pw.println("    sets and locks the thermal status of the device to STATUS.");
    580             pw.println("    status code is defined in android.os.Temperature.");
    581             pw.println("  reset");
    582             pw.println("    unlocks the thermal status of the device.");
    583             pw.println();
    584         }
    585     }
    586 
    587     abstract static class ThermalHalWrapper {
    588         protected static final String TAG = ThermalHalWrapper.class.getSimpleName();
    589 
    590         /** Lock to protect HAL handle. */
    591         protected final Object mHalLock = new Object();
    592 
    593         @FunctionalInterface
    594         interface TemperatureChangedCallback {
    595             void onValues(Temperature temperature);
    596         }
    597 
    598         /** Temperature callback. */
    599         protected TemperatureChangedCallback mCallback;
    600 
    601         /** Cookie for matching the right end point. */
    602         protected static final int THERMAL_HAL_DEATH_COOKIE = 5612;
    603 
    604         @VisibleForTesting
    605         protected void setCallback(TemperatureChangedCallback cb) {
    606             mCallback = cb;
    607         }
    608 
    609         protected abstract List<Temperature> getCurrentTemperatures(boolean shouldFilter,
    610                 int type);
    611 
    612         protected abstract List<CoolingDevice> getCurrentCoolingDevices(boolean shouldFilter,
    613                 int type);
    614 
    615         protected abstract boolean connectToHal();
    616 
    617         protected abstract void dump(PrintWriter pw, String prefix);
    618 
    619         protected void resendCurrentTemperatures() {
    620             synchronized (mHalLock) {
    621                 List<Temperature> temperatures = getCurrentTemperatures(false, 0);
    622                 final int count = temperatures.size();
    623                 for (int i = 0; i < count; i++) {
    624                     mCallback.onValues(temperatures.get(i));
    625                 }
    626             }
    627         }
    628 
    629         final class DeathRecipient implements HwBinder.DeathRecipient {
    630             @Override
    631             public void serviceDied(long cookie) {
    632                 if (cookie == THERMAL_HAL_DEATH_COOKIE) {
    633                     Slog.e(TAG, "Thermal HAL service died cookie: " + cookie);
    634                     synchronized (mHalLock) {
    635                         connectToHal();
    636                         // Post to listeners after reconnect to HAL.
    637                         resendCurrentTemperatures();
    638                     }
    639                 }
    640             }
    641         }
    642     }
    643 
    644 
    645     static class ThermalHal10Wrapper extends ThermalHalWrapper {
    646         /** Proxy object for the Thermal HAL 1.0 service. */
    647         @GuardedBy("mHalLock")
    648         private android.hardware.thermal.V1_0.IThermal mThermalHal10 = null;
    649 
    650         @Override
    651         protected List<Temperature> getCurrentTemperatures(boolean shouldFilter,
    652                 int type) {
    653             synchronized (mHalLock) {
    654                 List<Temperature> ret = new ArrayList<>();
    655                 if (mThermalHal10 == null) {
    656                     return ret;
    657                 }
    658                 try {
    659                     mThermalHal10.getTemperatures(
    660                             (ThermalStatus status,
    661                                     ArrayList<android.hardware.thermal.V1_0.Temperature>
    662                                             temperatures) -> {
    663                                 if (ThermalStatusCode.SUCCESS == status.code) {
    664                                     for (android.hardware.thermal.V1_0.Temperature
    665                                             temperature : temperatures) {
    666                                         if (shouldFilter && type != temperature.type) {
    667                                             continue;
    668                                         }
    669                                         // Thermal HAL 1.0 doesn't report current throttling status
    670                                         ret.add(new Temperature(
    671                                                 temperature.currentValue, temperature.type,
    672                                                 temperature.name,
    673                                                 Temperature.THROTTLING_NONE));
    674                                     }
    675                                 } else {
    676                                     Slog.e(TAG,
    677                                             "Couldn't get temperatures because of HAL error: "
    678                                                     + status.debugMessage);
    679                                 }
    680 
    681                             });
    682                 } catch (RemoteException e) {
    683                     Slog.e(TAG, "Couldn't getCurrentTemperatures, reconnecting...", e);
    684                     connectToHal();
    685                 }
    686                 return ret;
    687             }
    688         }
    689 
    690         @Override
    691         protected List<CoolingDevice> getCurrentCoolingDevices(boolean shouldFilter,
    692                 int type) {
    693             synchronized (mHalLock) {
    694                 List<CoolingDevice> ret = new ArrayList<>();
    695                 if (mThermalHal10 == null) {
    696                     return ret;
    697                 }
    698                 try {
    699                     mThermalHal10.getCoolingDevices((status, coolingDevices) -> {
    700                         if (ThermalStatusCode.SUCCESS == status.code) {
    701                             for (android.hardware.thermal.V1_0.CoolingDevice
    702                                     coolingDevice : coolingDevices) {
    703                                 if (shouldFilter && type != coolingDevice.type) {
    704                                     continue;
    705                                 }
    706                                 ret.add(new CoolingDevice(
    707                                         (long) coolingDevice.currentValue,
    708                                         coolingDevice.type,
    709                                         coolingDevice.name));
    710                             }
    711                         } else {
    712                             Slog.e(TAG,
    713                                     "Couldn't get cooling device because of HAL error: "
    714                                             + status.debugMessage);
    715                         }
    716 
    717                     });
    718                 } catch (RemoteException e) {
    719                     Slog.e(TAG, "Couldn't getCurrentCoolingDevices, reconnecting...", e);
    720                     connectToHal();
    721                 }
    722                 return ret;
    723             }
    724         }
    725 
    726         @Override
    727         protected boolean connectToHal() {
    728             synchronized (mHalLock) {
    729                 try {
    730                     mThermalHal10 = android.hardware.thermal.V1_0.IThermal.getService();
    731                     mThermalHal10.linkToDeath(new DeathRecipient(),
    732                             THERMAL_HAL_DEATH_COOKIE);
    733                     Slog.i(TAG,
    734                             "Thermal HAL 1.0 service connected, no thermal call back will be "
    735                                     + "called due to legacy API.");
    736                 } catch (NoSuchElementException | RemoteException e) {
    737                     Slog.e(TAG,
    738                             "Thermal HAL 1.0 service not connected.");
    739                     mThermalHal10 = null;
    740                 }
    741                 return (mThermalHal10 != null);
    742             }
    743         }
    744 
    745         @Override
    746         protected void dump(PrintWriter pw, String prefix) {
    747             synchronized (mHalLock) {
    748                 pw.print(prefix);
    749                 pw.println("ThermalHAL 1.0 connected: " + (mThermalHal10 != null ? "yes"
    750                         : "no"));
    751             }
    752         }
    753     }
    754 
    755     static class ThermalHal11Wrapper extends ThermalHalWrapper {
    756         /** Proxy object for the Thermal HAL 1.1 service. */
    757         @GuardedBy("mHalLock")
    758         private android.hardware.thermal.V1_1.IThermal mThermalHal11 = null;
    759 
    760         /** HWbinder callback for Thermal HAL 1.1. */
    761         private final IThermalCallback.Stub mThermalCallback11 =
    762                 new IThermalCallback.Stub() {
    763                     @Override
    764                     public void notifyThrottling(boolean isThrottling,
    765                             android.hardware.thermal.V1_0.Temperature temperature) {
    766                         Temperature thermalSvcTemp = new Temperature(
    767                                 temperature.currentValue, temperature.type, temperature.name,
    768                                 isThrottling ? ThrottlingSeverity.SEVERE
    769                                         : ThrottlingSeverity.NONE);
    770                         final long token = Binder.clearCallingIdentity();
    771                         try {
    772                             mCallback.onValues(thermalSvcTemp);
    773                         } finally {
    774                             Binder.restoreCallingIdentity(token);
    775                         }
    776                     }
    777                 };
    778 
    779         @Override
    780         protected List<Temperature> getCurrentTemperatures(boolean shouldFilter,
    781                 int type) {
    782             synchronized (mHalLock) {
    783                 List<Temperature> ret = new ArrayList<>();
    784                 if (mThermalHal11 == null) {
    785                     return ret;
    786                 }
    787                 try {
    788                     mThermalHal11.getTemperatures(
    789                             (ThermalStatus status,
    790                                     ArrayList<android.hardware.thermal.V1_0.Temperature>
    791                                             temperatures) -> {
    792                                 if (ThermalStatusCode.SUCCESS == status.code) {
    793                                     for (android.hardware.thermal.V1_0.Temperature
    794                                             temperature : temperatures) {
    795                                         if (shouldFilter && type != temperature.type) {
    796                                             continue;
    797                                         }
    798                                         // Thermal HAL 1.1 doesn't report current throttling status
    799                                         ret.add(new Temperature(
    800                                                 temperature.currentValue, temperature.type,
    801                                                 temperature.name,
    802                                                 Temperature.THROTTLING_NONE));
    803                                     }
    804                                 } else {
    805                                     Slog.e(TAG,
    806                                             "Couldn't get temperatures because of HAL error: "
    807                                                     + status.debugMessage);
    808                                 }
    809 
    810                             });
    811                 } catch (RemoteException e) {
    812                     Slog.e(TAG, "Couldn't getCurrentTemperatures, reconnecting...", e);
    813                     connectToHal();
    814                 }
    815                 return ret;
    816             }
    817         }
    818 
    819         @Override
    820         protected List<CoolingDevice> getCurrentCoolingDevices(boolean shouldFilter,
    821                 int type) {
    822             synchronized (mHalLock) {
    823                 List<CoolingDevice> ret = new ArrayList<>();
    824                 if (mThermalHal11 == null) {
    825                     return ret;
    826                 }
    827                 try {
    828                     mThermalHal11.getCoolingDevices((status, coolingDevices) -> {
    829                         if (ThermalStatusCode.SUCCESS == status.code) {
    830                             for (android.hardware.thermal.V1_0.CoolingDevice
    831                                     coolingDevice : coolingDevices) {
    832                                 if (shouldFilter && type != coolingDevice.type) {
    833                                     continue;
    834                                 }
    835                                 ret.add(new CoolingDevice(
    836                                         (long) coolingDevice.currentValue,
    837                                         coolingDevice.type,
    838                                         coolingDevice.name));
    839                             }
    840                         } else {
    841                             Slog.e(TAG,
    842                                     "Couldn't get cooling device because of HAL error: "
    843                                             + status.debugMessage);
    844                         }
    845 
    846                     });
    847                 } catch (RemoteException e) {
    848                     Slog.e(TAG, "Couldn't getCurrentCoolingDevices, reconnecting...", e);
    849                     connectToHal();
    850                 }
    851                 return ret;
    852             }
    853         }
    854 
    855         @Override
    856         protected boolean connectToHal() {
    857             synchronized (mHalLock) {
    858                 try {
    859                     mThermalHal11 = android.hardware.thermal.V1_1.IThermal.getService();
    860                     mThermalHal11.linkToDeath(new DeathRecipient(),
    861                             THERMAL_HAL_DEATH_COOKIE);
    862                     mThermalHal11.registerThermalCallback(mThermalCallback11);
    863                 } catch (NoSuchElementException | RemoteException e) {
    864                     Slog.e(TAG,
    865                             "Thermal HAL 1.1 service not connected, no thermal call back will be "
    866                                     + "called.");
    867                     mThermalHal11 = null;
    868                 }
    869                 return (mThermalHal11 != null);
    870             }
    871         }
    872 
    873         @Override
    874         protected void dump(PrintWriter pw, String prefix) {
    875             synchronized (mHalLock) {
    876                 pw.print(prefix);
    877                 pw.println("ThermalHAL 1.1 connected: " + (mThermalHal11 != null ? "yes"
    878                         : "no"));
    879             }
    880         }
    881     }
    882 
    883     static class ThermalHal20Wrapper extends ThermalHalWrapper {
    884         /** Proxy object for the Thermal HAL 2.0 service. */
    885         @GuardedBy("mHalLock")
    886         private android.hardware.thermal.V2_0.IThermal mThermalHal20 = null;
    887 
    888         /** HWbinder callback for Thermal HAL 2.0. */
    889         private final IThermalChangedCallback.Stub mThermalCallback20 =
    890                 new IThermalChangedCallback.Stub() {
    891                     @Override
    892                     public void notifyThrottling(
    893                             android.hardware.thermal.V2_0.Temperature temperature) {
    894                         Temperature thermalSvcTemp = new Temperature(
    895                                 temperature.value, temperature.type, temperature.name,
    896                                 temperature.throttlingStatus);
    897                         final long token = Binder.clearCallingIdentity();
    898                         try {
    899                             mCallback.onValues(thermalSvcTemp);
    900                         } finally {
    901                             Binder.restoreCallingIdentity(token);
    902                         }
    903                     }
    904                 };
    905 
    906         @Override
    907         protected List<Temperature> getCurrentTemperatures(boolean shouldFilter,
    908                 int type) {
    909             synchronized (mHalLock) {
    910                 List<Temperature> ret = new ArrayList<>();
    911                 if (mThermalHal20 == null) {
    912                     return ret;
    913                 }
    914                 try {
    915                     mThermalHal20.getCurrentTemperatures(shouldFilter, type,
    916                             (status, temperatures) -> {
    917                                 if (ThermalStatusCode.SUCCESS == status.code) {
    918                                     for (android.hardware.thermal.V2_0.Temperature
    919                                             temperature : temperatures) {
    920                                         ret.add(new Temperature(
    921                                                 temperature.value, temperature.type,
    922                                                 temperature.name,
    923                                                 temperature.throttlingStatus));
    924                                     }
    925                                 } else {
    926                                     Slog.e(TAG,
    927                                             "Couldn't get temperatures because of HAL error: "
    928                                                     + status.debugMessage);
    929                                 }
    930 
    931                             });
    932                 } catch (RemoteException e) {
    933                     Slog.e(TAG, "Couldn't getCurrentTemperatures, reconnecting...", e);
    934                     connectToHal();
    935                 }
    936                 return ret;
    937             }
    938         }
    939 
    940         @Override
    941         protected List<CoolingDevice> getCurrentCoolingDevices(boolean shouldFilter,
    942                 int type) {
    943             synchronized (mHalLock) {
    944                 List<CoolingDevice> ret = new ArrayList<>();
    945                 if (mThermalHal20 == null) {
    946                     return ret;
    947                 }
    948                 try {
    949                     mThermalHal20.getCurrentCoolingDevices(shouldFilter, type,
    950                             (status, coolingDevices) -> {
    951                                 if (ThermalStatusCode.SUCCESS == status.code) {
    952                                     for (android.hardware.thermal.V2_0.CoolingDevice
    953                                             coolingDevice : coolingDevices) {
    954                                         ret.add(new CoolingDevice(
    955                                                 coolingDevice.value, coolingDevice.type,
    956                                                 coolingDevice.name));
    957                                     }
    958                                 } else {
    959                                     Slog.e(TAG,
    960                                             "Couldn't get cooling device because of HAL error: "
    961                                                     + status.debugMessage);
    962                                 }
    963 
    964                             });
    965                 } catch (RemoteException e) {
    966                     Slog.e(TAG, "Couldn't getCurrentCoolingDevices, reconnecting...", e);
    967                     connectToHal();
    968                 }
    969                 return ret;
    970             }
    971         }
    972 
    973         @Override
    974         protected boolean connectToHal() {
    975             synchronized (mHalLock) {
    976                 try {
    977                     mThermalHal20 = android.hardware.thermal.V2_0.IThermal.getService();
    978                     mThermalHal20.linkToDeath(new DeathRecipient(), THERMAL_HAL_DEATH_COOKIE);
    979                     mThermalHal20.registerThermalChangedCallback(mThermalCallback20, false,
    980                             0 /* not used */);
    981                 } catch (NoSuchElementException | RemoteException e) {
    982                     Slog.e(TAG, "Thermal HAL 2.0 service not connected, trying 1.1.");
    983                     mThermalHal20 = null;
    984                 }
    985                 return (mThermalHal20 != null);
    986             }
    987         }
    988 
    989         @Override
    990         protected void dump(PrintWriter pw, String prefix) {
    991             synchronized (mHalLock) {
    992                 pw.print(prefix);
    993                 pw.println("ThermalHAL 2.0 connected: " + (mThermalHal20 != null ? "yes"
    994                         : "no"));
    995             }
    996         }
    997     }
    998 
    999 }
   1000