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