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 #define DEBUG false  // STOPSHIP if true
18 #include "Log.h"
19 
20 #include <android/hardware/thermal/1.0/IThermal.h>
21 #include "external/ResourceThermalManagerPuller.h"
22 #include "external/StatsPuller.h"
23 
24 #include "ResourceThermalManagerPuller.h"
25 #include "logd/LogEvent.h"
26 #include "statslog.h"
27 #include "stats_log_util.h"
28 
29 #include <chrono>
30 
31 using android::hardware::hidl_death_recipient;
32 using android::hardware::hidl_vec;
33 using android::hidl::base::V1_0::IBase;
34 using android::hardware::thermal::V1_0::IThermal;
35 using android::hardware::thermal::V1_0::Temperature;
36 using android::hardware::thermal::V1_0::ThermalStatus;
37 using android::hardware::thermal::V1_0::ThermalStatusCode;
38 using android::hardware::Return;
39 using android::hardware::Void;
40 
41 using std::chrono::duration_cast;
42 using std::chrono::nanoseconds;
43 using std::chrono::system_clock;
44 using std::make_shared;
45 using std::shared_ptr;
46 
47 namespace android {
48 namespace os {
49 namespace statsd {
50 
51 bool getThermalHalLocked();
52 sp<android::hardware::thermal::V1_0::IThermal> gThermalHal = nullptr;
53 std::mutex gThermalHalMutex;
54 
55 struct ThermalHalDeathRecipient : virtual public hidl_death_recipient {
serviceDiedandroid::os::statsd::ThermalHalDeathRecipient56       virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override {
57           std::lock_guard<std::mutex> lock(gThermalHalMutex);
58           ALOGE("ThermalHAL just died");
59           gThermalHal = nullptr;
60           getThermalHalLocked();
61       }
62 };
63 
64 sp<ThermalHalDeathRecipient> gThermalHalDeathRecipient = nullptr;
65 
66 // The caller must be holding gThermalHalMutex.
getThermalHalLocked()67 bool getThermalHalLocked() {
68     if (gThermalHal == nullptr) {
69             gThermalHal = IThermal::getService();
70             if (gThermalHal == nullptr) {
71                 ALOGE("Unable to get Thermal service.");
72             } else {
73                 if (gThermalHalDeathRecipient == nullptr) {
74                     gThermalHalDeathRecipient = new ThermalHalDeathRecipient();
75                 }
76                 hardware::Return<bool> linked = gThermalHal->linkToDeath(
77                     gThermalHalDeathRecipient, 0x451F /* cookie */);
78                 if (!linked.isOk()) {
79                     ALOGE("Transaction error in linking to ThermalHAL death: %s",
80                             linked.description().c_str());
81                     gThermalHal = nullptr;
82                 } else if (!linked) {
83                     ALOGW("Unable to link to ThermalHal death notifications");
84                     gThermalHal = nullptr;
85                 } else {
86                     ALOGD("Link to death notification successful");
87                 }
88             }
89     }
90     return gThermalHal != nullptr;
91 }
92 
ResourceThermalManagerPuller()93 ResourceThermalManagerPuller::ResourceThermalManagerPuller() :
94         StatsPuller(android::util::TEMPERATURE) {
95 }
96 
PullInternal(vector<shared_ptr<LogEvent>> * data)97 bool ResourceThermalManagerPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
98     std::lock_guard<std::mutex> lock(gThermalHalMutex);
99     if (!getThermalHalLocked()) {
100         ALOGE("Thermal Hal not loaded");
101         return false;
102     }
103 
104     int64_t wallClockTimestampNs = getWallClockNs();
105     int64_t elapsedTimestampNs = getElapsedRealtimeNs();
106 
107     data->clear();
108     bool resultSuccess = true;
109 
110     Return<void> ret = gThermalHal->getTemperatures(
111             [&](ThermalStatus status, const hidl_vec<Temperature>& temps) {
112         if (status.code != ThermalStatusCode::SUCCESS) {
113             ALOGE("Failed to get temperatures from ThermalHAL. Status: %d", status.code);
114             resultSuccess = false;
115             return;
116         }
117         if (mTagId == android::util::TEMPERATURE) {
118             for (size_t i = 0; i < temps.size(); ++i) {
119                 auto ptr = make_shared<LogEvent>(android::util::TEMPERATURE,
120                         wallClockTimestampNs, elapsedTimestampNs);
121                 ptr->write((static_cast<int>(temps[i].type)));
122                 ptr->write(temps[i].name);
123                 // Convert the temperature to an int.
124                 int32_t temp = static_cast<int>(temps[i].currentValue * 10);
125                 ptr->write(temp);
126                 ptr->init();
127                 data->push_back(ptr);
128             }
129         } else {
130             ALOGE("Unsupported tag in ResourceThermalManagerPuller: %d", mTagId);
131         }
132     });
133     if (!ret.isOk()) {
134         ALOGE("getThermalHalLocked() failed: thermal HAL service not available. Description: %s",
135                 ret.description().c_str());
136         if (ret.isDeadObject()) {
137             gThermalHal = nullptr;
138         }
139         return false;
140     }
141     return resultSuccess;
142 }
143 
144 }  // namespace statsd
145 }  // namespace os
146 }  // namespace android
147