/* * Copyright (C) 2013 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. */ #define TLOG_TAG "stats-relayer" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace android; using binder::Status; using frameworks::stats::VendorAtom; using frameworks::stats::VendorAtomValue; class StatsRelayer : public trusty::stats::tz::BnStats { public: class StatsSetterNormalWorld : public trusty::stats::nw::setter::BnStatsSetter { public: StatsSetterNormalWorld(sp&& statsRelayer) : mStatsRelayer(std::move(statsRelayer)) {} Status setInterface(const sp& istats) { assert(mStatsRelayer.get() != nullptr); TLOGD("setInterface from Normal-World Consumer\n"); // save iStats facet for asynchronous callback mStatsRelayer->mIStats = istats; return Status::ok(); }; private: sp mStatsRelayer; }; class StatsSetterSecureWorld : public trusty::stats::tz::BnStatsSetter { public: StatsSetterSecureWorld(sp&& statsRelayer) : mStatsRelayer(std::move(statsRelayer)) {} Status setInterface(const sp& istats) { assert(mStatsRelayer.get() != nullptr); TLOGD("setInterface from Secure World Consumer\n"); // callback into iStats synchronously if any atoms were previously // received. Swap so we don't try to report the same atoms twice // if we encounter an error. std::vector pending; std::swap(pending, mStatsRelayer->mPendingAtoms); for (const VendorAtom& atom : pending) { auto rc = istats->reportVendorAtom(atom); if (!rc.isOk()) { TLOGE("reportVendorAtom error %d\n", rc.exceptionCode()); return rc; } } return Status::ok(); } private: sp mStatsRelayer; }; StatsRelayer() : trusty::stats::tz::BnStats(), mPendingAtoms() {} Status reportVendorAtom(const VendorAtom& vendorAtom) { TLOGD("reportVendorAtom atomId=%d.\n", vendorAtom.atomId); if (mIStats) { /* * when the normal-world consumer initialises its binder session * with an incoming thread (setMaxIncomingThreads(1)), * its istats facet is accessible after the * setInterface returns. */ Status rc = mIStats->reportVendorAtom(vendorAtom); if (!rc.isOk()) { TLOGD("relaying reportVendorAtom failed=%d.\n", rc.exceptionCode()); return rc; } } /* * if istats endpoint is in secure-world, the callback path * is NOT persistent, hence istats pointer is valid only through the * setInterface call, so we record the vendorAtom so it * can be shared on a setInterface invocation */ mPendingAtoms.push_back(vendorAtom); return Status::ok(); } private: // the normal-world IStats facet, stored for asynchronous callback sp mIStats; // the vendor atom, stored to be shared to the consumer TA // via the synchronous callback std::vector mPendingAtoms; }; int main(void) { TLOGI("Starting StatsRelayer\n"); tipc_hset* hset = tipc_hset_create(); if (IS_ERR(hset)) { TLOGE("Failed to create handle set (%d)\n", PTR_ERR(hset)); return EXIT_FAILURE; } auto statsRelayer = sp::make(); auto statsSetterNormalWorld = sp::make(sp(statsRelayer)); auto statsSetterSecureWorld = sp::make(sp(statsRelayer)); const auto portAcl_TA = RpcServerTrusty::PortAcl{ .flags = IPC_PORT_ALLOW_TA_CONNECT, }; const auto portAcl_NS = RpcServerTrusty::PortAcl{ .flags = IPC_PORT_ALLOW_NS_CONNECT, }; // message size needs to be large enough to cover all messages sent by // the tests constexpr size_t maxMsgSize = 4096; TLOGE("Creating Relayer (exposing IStats)\n"); auto srvIStats = RpcServerTrusty::make( hset, RELAYER_PORT_ISTATS, std::make_shared(portAcl_TA), maxMsgSize); if (srvIStats == nullptr) { return EXIT_FAILURE; } srvIStats->setRootObject(statsRelayer); // expose the test port for the NW accessible IStatsSetter interface // trusty::stats::setter::IStatsSetter auto srvIStatsSetterNormalWorld = RpcServerTrusty::make( hset, RELAYER_PORT_ISTATS_SETTER_NORMAL_WORLD, std::make_shared(portAcl_NS), maxMsgSize); if (srvIStatsSetterNormalWorld == nullptr) { return EXIT_FAILURE; } srvIStatsSetterNormalWorld->setRootObject(statsSetterNormalWorld); auto srvIStatsSetterSecureWorld = RpcServerTrusty::make( hset, RELAYER_PORT_ISTATS_SETTER_SECURE_WORLD, std::make_shared(portAcl_TA), maxMsgSize); if (srvIStatsSetterSecureWorld == nullptr) { return EXIT_FAILURE; } srvIStatsSetterSecureWorld->setRootObject(statsSetterSecureWorld); int rc = tipc_run_event_loop(hset); TLOGE("stats-relayer service died\n"); return rc; }