/** * Copyright (c) 2020, 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. */ #ifndef CPP_WATCHDOG_SERVER_SRC_WATCHDOGPROCESSSERVICE_H_ #define CPP_WATCHDOG_SERVER_SRC_WATCHDOGPROCESSSERVICE_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace android { namespace automotive { namespace watchdog { // Forward declaration for testing use only. namespace internal { class WatchdogProcessServicePeer; } // namespace internal class WatchdogServiceHelperInterface; class WatchdogProcessServiceInterface : public android::RefBase { public: virtual android::base::Result start() = 0; virtual void terminate() = 0; virtual android::base::Result dump(int fd, const android::Vector& args) = 0; virtual void doHealthCheck(int what) = 0; virtual android::base::Result registerWatchdogServiceHelper( const android::sp& helper) = 0; virtual android::binder::Status registerClient(const android::sp& client, TimeoutLength timeout) = 0; virtual android::binder::Status unregisterClient( const android::sp& client) = 0; virtual android::binder::Status registerCarWatchdogService( const android::sp& binder) = 0; virtual void unregisterCarWatchdogService(const android::sp& binder) = 0; virtual android::binder::Status registerMonitor( const android::sp& monitor) = 0; virtual android::binder::Status unregisterMonitor( const android::sp& monitor) = 0; virtual android::binder::Status tellClientAlive(const android::sp& client, int32_t sessionId) = 0; virtual android::binder::Status tellCarWatchdogServiceAlive( const android::sp< android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>& service, const std::vector& clientsNotResponding, int32_t sessionId) = 0; virtual android::binder::Status tellDumpFinished( const android::sp& monitor, const android::automotive::watchdog::internal::ProcessIdentifier& processIdentifier) = 0; virtual void setEnabled(bool isEnabled) = 0; virtual void onUserStateChange(userid_t userId, bool isStarted) = 0; }; class WatchdogProcessService final : public WatchdogProcessServiceInterface { public: explicit WatchdogProcessService(const android::sp& handlerLooper); ~WatchdogProcessService() { terminate(); } android::base::Result start(); void terminate(); virtual android::base::Result dump(int fd, const android::Vector& args); void doHealthCheck(int what); virtual android::base::Result registerWatchdogServiceHelper( const android::sp& helper); virtual android::binder::Status registerClient(const android::sp& client, TimeoutLength timeout); virtual android::binder::Status unregisterClient(const android::sp& client); virtual android::binder::Status registerCarWatchdogService(const android::sp& binder); virtual void unregisterCarWatchdogService(const android::sp& binder); virtual android::binder::Status registerMonitor( const android::sp& monitor); virtual android::binder::Status unregisterMonitor( const android::sp& monitor); virtual android::binder::Status tellClientAlive(const android::sp& client, int32_t sessionId); virtual android::binder::Status tellCarWatchdogServiceAlive( const android::sp< android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>& service, const std::vector& clientsNotResponding, int32_t sessionId); virtual android::binder::Status tellDumpFinished( const android::sp& monitor, const android::automotive::watchdog::internal::ProcessIdentifier& processIdentifier); virtual void setEnabled(bool isEnabled); virtual void onUserStateChange(userid_t userId, bool isStarted); private: enum ClientType { Regular, Service, }; class ClientInfo { public: ClientInfo(const android::sp& client, pid_t pid, userid_t userId, uint64_t startTimeMillis) : pid(pid), userId(userId), startTimeMillis(startTimeMillis), type(ClientType::Regular), client(client) {} ClientInfo(const android::sp& helper, const android::sp& binder, pid_t pid, userid_t userId, uint64_t startTimeMillis) : pid(pid), userId(userId), startTimeMillis(startTimeMillis), type(ClientType::Service), watchdogServiceHelper(helper), watchdogServiceBinder(binder) {} std::string toString() const; status_t linkToDeath(const android::sp& recipient) const; status_t unlinkToDeath( const android::wp& recipient) const; android::binder::Status checkIfAlive(TimeoutLength timeout) const; android::binder::Status prepareProcessTermination() const; bool operator!=(const ClientInfo& clientInfo) const { return getBinder() != clientInfo.getBinder() || type != clientInfo.type; } bool matchesBinder(const android::sp& binder) const { return binder == getBinder(); } pid_t pid; userid_t userId; int64_t startTimeMillis; int sessionId; private: android::sp getBinder() const; ClientType type; android::sp client = nullptr; android::sp watchdogServiceHelper = nullptr; android::sp watchdogServiceBinder = nullptr; }; struct HeartBeat { int64_t eventTime; int64_t value; }; typedef std::unordered_map PingedClientMap; class BinderDeathRecipient final : public android::IBinder::DeathRecipient { public: explicit BinderDeathRecipient(const android::sp& service); void binderDied(const android::wp& who) override; private: android::sp mService; }; class PropertyChangeListener final : public android::frameworks::automotive::vhal::ISubscriptionCallback { public: explicit PropertyChangeListener(const android::sp& service); void onPropertyEvent(const std::vector< std::unique_ptr>& values) override; void onPropertySetError( const std::vector& errors) override; private: android::sp mService; }; class MessageHandlerImpl final : public MessageHandler { public: explicit MessageHandlerImpl(const android::sp& service); void handleMessage(const Message& message) override; private: android::sp mService; }; private: android::binder::Status registerClient(const ClientInfo& clientInfo, TimeoutLength timeout); android::binder::Status unregisterClientLocked(const std::vector& timeouts, android::sp binder, ClientType clientType); android::binder::Status tellClientAliveLocked(const android::sp& binder, int32_t sessionId); android::base::Result startHealthCheckingLocked(TimeoutLength timeout); android::base::Result dumpAndKillClientsIfNotResponding(TimeoutLength timeout); android::base::Result dumpAndKillAllProcesses( const std::vector& processesNotResponding, bool reportToVhal); int32_t getNewSessionId(); android::base::Result updateVhal( const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value); android::base::Result connectToVhalLocked(); void subscribeToVhalHeartBeatLocked(); bool cacheVhalProcessIdentifier(); void reportWatchdogAliveToVhal(); void reportTerminatedProcessToVhal( const std::vector& processesNotResponding); android::base::Result readProcCmdLine(int32_t pid); void handleBinderDeath(const android::wp& who); void handleVhalDeath(); void queryVhalPropertiesLocked(); bool isVhalPropertySupportedLocked( aidl::android::hardware::automotive::vehicle::VehicleProperty propId); void updateVhalHeartBeat(int64_t value); void checkVhalHealth(); void terminateVhal(); using Processor = std::function&, std::vector::const_iterator)>; bool findClientAndProcessLocked(const std::vector timeouts, const ClientInfo& clientInfo, const Processor& processor); bool findClientAndProcessLocked(const std::vector timeouts, const android::sp binder, const Processor& processor); std::chrono::nanoseconds getTimeoutDurationNs(const TimeoutLength& timeout); private: android::sp mHandlerLooper; android::sp mMessageHandler; std::unordered_set mNotSupportedVhalProperties; std::shared_ptr mPropertyChangeListener; // mLastSessionId is accessed only within main thread. No need for mutual-exclusion. int32_t mLastSessionId; bool mServiceStarted; std::chrono::milliseconds mVhalHealthCheckWindowMs; std::optional mOverriddenClientHealthCheckWindowNs; std::shared_ptr mOnBinderDiedCallback; std::function mGetStartTimeForPidFunc; android::Mutex mMutex; std::unordered_map> mClients GUARDED_BY(mMutex); std::unordered_map mPingedClients GUARDED_BY(mMutex); std::unordered_set mStoppedUserIds GUARDED_BY(mMutex); android::sp mMonitor GUARDED_BY(mMutex); bool mIsEnabled GUARDED_BY(mMutex); std::shared_ptr mVhalService GUARDED_BY(mMutex); std::optional mVhalProcessIdentifier GUARDED_BY(mMutex); HeartBeat mVhalHeartBeat GUARDED_BY(mMutex); android::sp mWatchdogServiceHelper GUARDED_BY(mMutex); android::sp mBinderDeathRecipient GUARDED_BY(mMutex); // For unit tests. friend class internal::WatchdogProcessServicePeer; }; } // namespace watchdog } // namespace automotive } // namespace android #endif // CPP_WATCHDOG_SERVER_SRC_WATCHDOGPROCESSSERVICE_H_