/** * 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 namespace android { namespace automotive { namespace watchdog { class IWatchdogServiceHelper; class WatchdogProcessService : public android::RefBase { 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, int32_t pid); virtual void setEnabled(bool isEnabled); virtual void notifyUserStateChange(userid_t userId, bool isStarted); private: enum ClientType { Regular, Service, }; struct ClientInfo { ClientInfo(const android::sp& client, pid_t pid, userid_t userId) : pid(pid), userId(userId), type(ClientType::Regular), client(client) {} ClientInfo(const android::sp& helper, const android::sp& binder, pid_t pid, userid_t userId) : pid(pid), userId(userId), 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; 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 : public android::IBinder::DeathRecipient { public: explicit BinderDeathRecipient(const android::sp& service); void binderDied(const android::wp& who) override; private: android::sp mService; }; class HidlDeathRecipient : public android::hardware::hidl_death_recipient { public: explicit HidlDeathRecipient(const android::sp& service); void serviceDied(uint64_t cookie, const android::wp& who) override; private: android::sp mService; }; class PropertyChangeListener : public android::hardware::automotive::vehicle::V2_0::IVehicleCallback { public: explicit PropertyChangeListener(const android::sp& service); android::hardware::Return onPropertyEvent( const android::hardware::hidl_vec< android::hardware::automotive::vehicle::V2_0::VehiclePropValue>& propValues) override; android::hardware::Return onPropertySet( const android::hardware::automotive::vehicle::V2_0::VehiclePropValue& propValue) override; android::hardware::Return onPropertySetError( android::hardware::automotive::vehicle::V2_0::StatusCode errorCode, int32_t propId, int32_t areaId) override; private: android::sp mService; }; class MessageHandlerImpl : public MessageHandler { public: explicit MessageHandlerImpl(const android::sp& service); void handleMessage(const Message& message) override; private: android::sp mService; }; private: android::binder::Status registerClientLocked(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 android::hardware::automotive::vehicle::V2_0::VehiclePropValue& value); android::base::Result connectToVhalLocked(); void subscribeToVhalHeartBeatLocked(); void reportWatchdogAliveToVhal(); void reportTerminatedProcessToVhal(const std::vector& processesNotResponding); android::base::Result readProcCmdLine(int32_t pid); void handleBinderDeath(const android::wp& who); void handleHidlDeath(const android::wp& who); void queryVhalPropertiesLocked(); bool isVhalPropertySupportedLocked( android::hardware::automotive::vehicle::V2_0::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); private: android::sp mHandlerLooper; android::sp mMessageHandler; 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); // mLastSessionId is accessed only within main thread. No need for mutual-exclusion. int32_t mLastSessionId; bool mServiceStarted; android::sp mVhalService GUARDED_BY(mMutex); android::sp mBinderDeathRecipient; android::sp mHidlDeathRecipient; std::unordered_set mNotSupportedVhalProperties; android::sp mPropertyChangeListener; HeartBeat mVhalHeartBeat GUARDED_BY(mMutex); std::chrono::milliseconds mVhalHealthCheckWindowMs; android::sp mWatchdogServiceHelper GUARDED_BY(mMutex); }; } // namespace watchdog } // namespace automotive } // namespace android #endif // CPP_WATCHDOG_SERVER_SRC_WATCHDOGPROCESSSERVICE_H_