1 /*
2 * Copyright (C) 2017 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 #include <algorithm>
18 #include <chrono>
19 #include <condition_variable>
20 #include <functional>
21 #include <future>
22 #include <iomanip>
23 #include <limits>
24 #include <mutex>
25 #include <thread>
26
27 #include <android-base/logging.h>
28 #include <binder/IBinder.h>
29 #include <binder/IPCThreadState.h>
30 #include <binder/IServiceManager.h>
31
32 #include <app_nugget.h>
33 #include <citadel_events.h>
34 #include <nos/NuggetClient.h>
35 #include <nos/device.h>
36
37 #include <android/hardware/citadel/BnCitadeld.h>
38
39 #include <android/vendor/powerstats/BnPixelPowerStatsCallback.h>
40 #include <android/vendor/powerstats/BnPixelPowerStatsProvider.h>
41 #include <android/vendor/powerstats/StateResidencyData.h>
42
43 using ::android::defaultServiceManager;
44 using ::android::IPCThreadState;
45 using ::android::IServiceManager;
46 using ::android::OK;
47 using ::android::ProcessState;
48 using ::android::sp;
49 using ::android::status_t;
50 using ::android::wp;
51 using ::android::binder::Status;
52
53 using ::nos::NuggetClient;
54
55 using ::android::hardware::citadel::BnCitadeld;
56 using ::android::hardware::citadel::ICitadeld;
57
58 using android::IBinder;
59 using android::vendor::powerstats::BnPixelPowerStatsCallback;
60 using android::vendor::powerstats::IPixelPowerStatsProvider;
61 using android::vendor::powerstats::StateResidencyData;
62
63 namespace {
64
65 using namespace std::chrono_literals;
66
67 // This attaches a timer to a function call. Call .schedule() to start the
68 // timer, and the function will be called (once) after the time has elapsed. If
69 // you call .schedule() again before that happens, it just restarts the timer.
70 // There's no way to cancel the function call after it's scheduled; you can only
71 // postpone it.
72 class DeferredCallback {
73 public:
DeferredCallback(std::chrono::milliseconds delay,std::function<void ()> fn)74 DeferredCallback(std::chrono::milliseconds delay, std::function<void()> fn)
75 : _armed(false),
76 _delay(delay),
77 _func(fn),
78 _waiter_thread(std::bind(&DeferredCallback::waiter_task, this)) {}
~DeferredCallback()79 ~DeferredCallback() {}
80
81 // [re]start the timer for the delayed call
schedule()82 void schedule() {
83 std::unique_lock<std::mutex> _lock(_cv_mutex);
84 _armed = true;
85 _cv.notify_one();
86 }
87
88 private:
waiter_task(void)89 void waiter_task(void) {
90 std::unique_lock<std::mutex> _lock(_cv_mutex);
91 while (true) {
92 if (!_armed) {
93 _cv.wait(_lock);
94 }
95 auto timeout = std::chrono::steady_clock::now() + _delay;
96 if (_cv.wait_until(_lock, timeout) == std::cv_status::timeout) {
97 _func();
98 _armed = false;
99 }
100 }
101 }
102
103 bool _armed;
104 const std::chrono::milliseconds _delay;
105 const std::function<void()> _func;
106 std::thread _waiter_thread;
107 std::mutex _cv_mutex;
108 std::condition_variable _cv;
109 };
110
111 // This provides a Binder interface for the powerstats service to fetch our
112 // power stats info from. This is a secondary function of citadeld. Failures
113 // here must not block or delay AP/Citadel communication.
114 class StatsDelegate : public BnPixelPowerStatsCallback,
115 public IBinder::DeathRecipient {
116 public:
StatsDelegate(std::function<Status (std::vector<StateResidencyData> *)> fn)117 StatsDelegate(std::function<Status(std::vector<StateResidencyData>*)> fn)
118 : func_(fn) {}
119
120 // methods from BnPixelPowerStatsCallback
getStats(std::vector<StateResidencyData> * stats)121 virtual Status getStats(std::vector<StateResidencyData>* stats) override {
122 return func_(stats);
123 }
124
125 // methods from IBinder::DeathRecipient
onAsBinder()126 virtual IBinder* onAsBinder() override { return this; }
binderDied(const wp<IBinder> & who)127 virtual void binderDied(const wp<IBinder>& who) override {
128 LOG(INFO) << "powerstats service died";
129 const sp<IBinder>& service = who.promote();
130 if (service != nullptr) {
131 service->unlinkToDeath(this);
132 }
133 sp<IBinder> powerstats_service = WaitForPowerStatsService();
134 registerWithPowerStats(powerstats_service);
135 }
136
137 // post-creation init (Binder calls inside constructor are troublesome)
registerWithPowerStats(sp<IBinder> & powerstats_service)138 void registerWithPowerStats(sp<IBinder>& powerstats_service) {
139 sp<IPixelPowerStatsProvider> powerstats_provider =
140 android::interface_cast<IPixelPowerStatsProvider>(
141 powerstats_service);
142
143 LOG(INFO) << "signing up for a notification if powerstats dies";
144 auto ret = asBinder(powerstats_provider)
145 ->linkToDeath(this, 0u /* cookie */);
146 if (ret != android::OK) {
147 LOG(ERROR) << "linkToDeath() returned " << ret
148 << " - we will NOT be notified on powerstats death";
149 }
150
151 LOG(INFO) << "registering our callback with powerstats service";
152 Status status = powerstats_provider->registerCallback("Citadel", this);
153 if (!status.isOk()) {
154 LOG(ERROR) << "failed to register callback: " << status.toString8();
155 }
156 }
157
158 // static helper function
WaitForPowerStatsService()159 static sp<IBinder> WaitForPowerStatsService() {
160 LOG(INFO) << "waiting for powerstats service to appear";
161 sp<IBinder> svc;
162 while (true) {
163 svc = defaultServiceManager()->checkService(
164 android::String16("power.stats-vendor"));
165 if (svc != nullptr) {
166 LOG(INFO) << "A wild powerstats service has appeared!";
167 return svc;
168 }
169 sleep(1);
170 }
171 }
172
173 // Creates a new StatsDelegate only after a powerstats service becomes
174 // available for it to register with.
MakeOne(std::function<Status (std::vector<StateResidencyData> *)> fn)175 static sp<StatsDelegate> MakeOne(
176 std::function<Status(std::vector<StateResidencyData>*)> fn) {
177 sp<IBinder> powerstats_service =
178 StatsDelegate::WaitForPowerStatsService();
179 sp<StatsDelegate> sd = new StatsDelegate(fn);
180 sd->registerWithPowerStats(powerstats_service);
181 return sd;
182 }
183
184 private:
185 const std::function<Status(std::vector<StateResidencyData>*)> func_;
186 };
187
188 class CitadelProxy : public BnCitadeld {
189 public:
CitadelProxy(NuggetClient & client)190 CitadelProxy(NuggetClient& client)
191 : _client{client},
192 _event_thread(std::bind(&CitadelProxy::dispatchEvents, this)),
193 _stats_collection(500ms, std::bind(&CitadelProxy::cacheStats, this)) {
194 }
195 ~CitadelProxy() override = default;
196
197 // methods from BnCitadeld
198
callApp(const int32_t _appId,const int32_t _arg,const std::vector<uint8_t> & request,std::vector<uint8_t> * const response,int32_t * const _aidl_return)199 Status callApp(const int32_t _appId, const int32_t _arg,
200 const std::vector<uint8_t>& request,
201 std::vector<uint8_t>* const response,
202 int32_t* const _aidl_return) override {
203 // AIDL doesn't support integers less than 32-bit so validate it before
204 // casting
205 if (_appId < 0 || _appId > kMaxAppId) {
206 LOG(ERROR) << "App ID " << _appId << " is outside the app ID range";
207 return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
208 }
209 if (_arg < 0 || _arg > std::numeric_limits<uint16_t>::max()) {
210 LOG(ERROR) << "Argument " << _arg
211 << " is outside the unsigned 16-bit range";
212 return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
213 }
214
215 const uint8_t appId = static_cast<uint32_t>(_appId);
216 const uint16_t arg = static_cast<uint16_t>(_arg);
217 uint32_t* const appStatus = reinterpret_cast<uint32_t*>(_aidl_return);
218 *appStatus = lockedCallApp(appId, arg, request, response);
219
220 _stats_collection.schedule();
221
222 return Status::ok();
223 }
224
reset(bool * const _aidl_return)225 Status reset(bool* const _aidl_return) override {
226 // This doesn't use the transport API to talk to any app so doesn't need
227 // to hold any app locks.
228 const nos_device& device = *_client.Device();
229 *_aidl_return = (device.ops.reset(device.ctx) == 0);
230 return Status::ok();
231 }
232
getCachedStats(std::vector<uint8_t> * const response)233 Status getCachedStats(std::vector<uint8_t>* const response) override {
234 std::unique_lock<std::mutex> lock(_stats_mutex);
235 response->resize(sizeof(_stats));
236 memcpy(response->data(), &_stats, sizeof(_stats));
237 return Status::ok();
238 }
239
240 // Interaction with the powerstats service is handled by the StatsDelegate
241 // class, but its getStats() method calls this to access our cached stats.
onGetStats(std::vector<StateResidencyData> * stats)242 Status onGetStats(std::vector<StateResidencyData>* stats) {
243 std::unique_lock<std::mutex> lock(_stats_mutex);
244
245 StateResidencyData data1;
246 data1.state = "Last-Reset";
247 data1.totalTimeInStateMs = _stats.time_since_hard_reset / 1000;
248 data1.totalStateEntryCount = _stats.hard_reset_count;
249 data1.lastEntryTimestampMs = 0;
250 stats->emplace_back(data1);
251
252 StateResidencyData data2;
253 data2.state = "Active";
254 data2.totalTimeInStateMs = _stats.time_spent_awake / 1000;
255 data2.totalStateEntryCount = _stats.wake_count;
256 data2.lastEntryTimestampMs = _stats.time_at_last_wake / 1000;
257 stats->emplace_back(data2);
258
259 StateResidencyData data3;
260 data3.state = "Deep-Sleep";
261 data3.totalTimeInStateMs = _stats.time_spent_in_deep_sleep / 1000;
262 data3.totalStateEntryCount = _stats.deep_sleep_count;
263 data3.lastEntryTimestampMs = _stats.time_at_last_deep_sleep / 1000;
264 stats->emplace_back(data3);
265
266 return Status::ok();
267 }
268
269 private:
270 static constexpr auto kMaxAppId = std::numeric_limits<uint8_t>::max();
271
272 NuggetClient& _client;
273 std::thread _event_thread;
274 std::mutex _appLocks[kMaxAppId + 1];
275 struct nugget_app_low_power_stats _stats;
276 DeferredCallback _stats_collection;
277 std::mutex _stats_mutex;
278
279 // Make the call to the app while holding the lock for that app
lockedCallApp(uint32_t appId,uint16_t arg,const std::vector<uint8_t> & request,std::vector<uint8_t> * response)280 uint32_t lockedCallApp(uint32_t appId, uint16_t arg,
281 const std::vector<uint8_t>& request,
282 std::vector<uint8_t>* response) {
283 std::unique_lock<std::mutex> lock(_appLocks[appId]);
284 return _client.CallApp(appId, arg, request, response);
285 }
286
cacheStats(void)287 void cacheStats(void) {
288 std::vector<uint8_t> buffer;
289
290 buffer.reserve(sizeof(_stats));
291 uint32_t rv = lockedCallApp(APP_ID_NUGGET,
292 NUGGET_PARAM_GET_LOW_POWER_STATS, buffer,
293 &buffer);
294 if (rv == APP_SUCCESS) {
295 std::unique_lock<std::mutex> lock(_stats_mutex);
296 memcpy(&_stats, buffer.data(),
297 std::min(sizeof(_stats), buffer.size()));
298 }
299 }
300
dispatchEvents(void)301 [[noreturn]] void dispatchEvents(void) {
302 LOG(INFO) << "Event dispatcher startup.";
303
304 const nos_device& device = *_client.Device();
305
306 while (true) {
307
308 const int wait_rv = device.ops.wait_for_interrupt(device.ctx, -1);
309 if (wait_rv <= 0) {
310 LOG(WARNING) << "device.ops.wait_for_interrupt: " << wait_rv;
311 continue;
312 }
313
314 // CTDL_AP_IRQ is asserted, fetch all the event_records from Citadel
315 while (true) {
316 struct event_record evt;
317 std::vector<uint8_t> buffer;
318 buffer.reserve(sizeof(evt));
319 const uint32_t rv = lockedCallApp(APP_ID_NUGGET,
320 NUGGET_PARAM_GET_EVENT_RECORD,
321 buffer, &buffer);
322 if (rv != APP_SUCCESS) {
323 LOG(WARNING) << "failed to fetch event_record: " << rv;
324 break;
325 }
326
327 if (buffer.size() == 0) {
328 // Success but no data means we've fetched them all
329 break;
330 }
331
332 // TODO(b/34946126): Do something more than just log it
333 memcpy(&evt, buffer.data(), sizeof(evt));
334 const uint64_t secs = evt.uptime_usecs / 1000000UL;
335 const uint64_t usecs = evt.uptime_usecs - (secs * 1000000UL);
336 LOG(INFO) << std::setfill('0') << std::internal
337 << "event_record " << evt.reset_count << "/"
338 << secs << "." << std::setw(6) << usecs
339 << " " << evt.id
340 << std::hex
341 << " 0x" << std::setw(8) << evt.u.raw.w[0]
342 << " 0x" << std::setw(8) << evt.u.raw.w[1]
343 << " 0x" << std::setw(8) << evt.u.raw.w[2];
344 }
345
346 // TODO: Add a more intelligent back-off (and other action?) here
347 //
348 // When Citadel indicates that it has event_records for us, we fetch
349 // one at a time without delay until we've gotten them all (and then
350 // wait a bit to give it time to deassert CTDL_AP_IRQ).
351 //
352 // OTOH, if Citadel is just constantly asserting CTDL_AP_IRQ but
353 // doesn't actually have any events for us, then a) that's probably
354 // a bug, and b) we shouldn't spin madly here just querying it over
355 // and over.
356 sleep(1);
357 }
358 }
359 };
360
361 } // namespace
362
main()363 int main() {
364 LOG(INFO) << "Starting citadeld";
365
366 // Connect to Citadel
367 NuggetClient citadel;
368 citadel.Open();
369 if (!citadel.IsOpen()) {
370 LOG(FATAL) << "Failed to open Citadel client";
371 }
372
373 // Citadel HALs will communicate with this daemon via /dev/vndbinder as this
374 // is vendor code
375 ProcessState::initWithDriver("/dev/vndbinder");
376
377 sp<CitadelProxy> proxy = new CitadelProxy(citadel);
378 const status_t status = defaultServiceManager()->addService(ICitadeld::descriptor, proxy);
379 if (status != OK) {
380 LOG(FATAL) << "Failed to register citadeld as a service (status " << status << ")";
381 return 1;
382 }
383
384 // We'll create a StatsDelegate object to talk to the powerstats service,
385 // but it will need a function to access the stats we've cached in the
386 // CitadelProxy object.
387 std::function<Status(std::vector<StateResidencyData>*)> fn =
388 std::bind(&CitadelProxy::onGetStats, proxy, std::placeholders::_1);
389
390 // Use a separate thread to wait for the powerstats service to appear, so
391 // the Citadel proxy can start working ASAP.
392 std::future<sp<StatsDelegate>> sd =
393 std::async(std::launch::async, StatsDelegate::MakeOne, fn);
394
395 // Start handling binder requests with multiple threads
396 ProcessState::self()->startThreadPool();
397 IPCThreadState::self()->joinThreadPool();
398
399 return 0;
400 }
401