/******************************************************************************* * Copyright (c) 2011, 2016 Eurotech and/or its affiliates * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.emulator.watchdog; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.watchdog.CriticalComponent; import org.eclipse.kura.watchdog.WatchdogService; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class WatchdogServiceImpl implements WatchdogService, ConfigurableComponent { private static final Logger s_logger = LoggerFactory.getLogger(WatchdogServiceImpl.class); private Map<String, Object> m_properties; private ScheduledExecutorService m_executor; private ScheduledFuture<?> m_future; private int pingInterval = 10000; // milliseconds private static ArrayList<CriticalServiceImpl> s_criticalServiceList; private boolean m_configEnabled = false; // initialized in properties, if false -> no watchdog private boolean m_enabled; protected void activate(ComponentContext componentContext, Map<String, Object> properties) { this.m_properties = properties; if (properties == null) { s_logger.debug("activating WatchdogService with null props"); } else { s_logger.debug("activating WatchdogService with {}", properties.toString()); } s_criticalServiceList = new ArrayList<CriticalServiceImpl>(); this.m_enabled = false; // clean up if this is not our first run if (this.m_executor != null) { this.m_executor.shutdown(); while (!this.m_executor.isTerminated()) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } this.m_executor = null; } this.m_executor = Executors.newSingleThreadScheduledExecutor(); this.m_future = this.m_executor.scheduleAtFixedRate(new Runnable() { @Override public void run() { Thread.currentThread().setName(getClass().getSimpleName()); if (WatchdogServiceImpl.this.m_configEnabled) { doWatchdogLoop(); } } }, 0, this.pingInterval, TimeUnit.MILLISECONDS); } protected void deactivate(ComponentContext componentContext) { this.m_executor.shutdown(); while (!this.m_executor.isTerminated()) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } this.m_executor = null; s_criticalServiceList = null; } public void updated(Map<String, Object> properties) { s_logger.debug("updated..."); this.m_properties = properties; if (this.m_properties != null) { if (this.m_properties.get("enabled") != null) { if (this.m_properties.get("enabled") != null) { this.m_configEnabled = (Boolean) this.m_properties.get("enabled"); } } if (!this.m_configEnabled) { return; } if (this.m_properties.get("pingInterval") != null) { this.pingInterval = (Integer) this.m_properties.get("pingInterval"); if (this.m_future != null) { this.m_future.cancel(false); while (!this.m_future.isDone()) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } this.m_future = this.m_executor.scheduleAtFixedRate(new Runnable() { @Override public void run() { Thread.currentThread().setName(getClass().getSimpleName()); if (WatchdogServiceImpl.this.m_configEnabled) { doWatchdogLoop(); } } }, 0, this.pingInterval, TimeUnit.MILLISECONDS); } } } @Override public void startWatchdog() { this.m_enabled = true; } @Override public void stopWatchdog() { this.m_enabled = false; } @Override public int getHardwareTimeout() { return 0; } @Override public void registerCriticalComponent(CriticalComponent criticalComponent) { final CriticalServiceImpl service = new CriticalServiceImpl(criticalComponent.getCriticalComponentName(), criticalComponent.getCriticalComponentTimeout()); synchronized (s_criticalServiceList) { // avoid to add same component twice (eg in case of a package updating) boolean existing = false; for (CriticalServiceImpl csi : s_criticalServiceList) { if (criticalComponent.getCriticalComponentName().compareTo(csi.getName()) == 0) { existing = true; } } if (!existing) { s_criticalServiceList.add(service); } } s_logger.debug("Added " + criticalComponent.getCriticalComponentName() + ", with timeout = " + criticalComponent.getCriticalComponentTimeout() + ", list contains " + s_criticalServiceList.size() + " critical services"); } @Override @Deprecated public void registerCriticalService(CriticalComponent criticalComponent) { registerCriticalComponent(criticalComponent); } @Override public void unregisterCriticalComponent(CriticalComponent criticalComponent) { synchronized (s_criticalServiceList) { for (int i = 0; i < s_criticalServiceList.size(); i++) { if (criticalComponent.getCriticalComponentName() .compareTo(s_criticalServiceList.get(i).getName()) == 0) { s_criticalServiceList.remove(i); s_logger.debug("Critical service " + criticalComponent.getCriticalComponentName() + " removed, " + System.currentTimeMillis()); } } } } @Override public void unregisterCriticalService(CriticalComponent criticalComponent) { unregisterCriticalComponent(criticalComponent); } @Override public List<CriticalComponent> getCriticalComponents() { return null; } @Override public void checkin(CriticalComponent criticalService) { synchronized (s_criticalServiceList) { for (CriticalServiceImpl csi : s_criticalServiceList) { if (criticalService.getCriticalComponentName().compareTo(csi.getName()) == 0) { csi.update(); } } } } private void doWatchdogLoop() { if (!this.m_enabled) { return; } boolean failure = false; // Critical Services synchronized (s_criticalServiceList) { if (!s_criticalServiceList.isEmpty()) { for (CriticalServiceImpl csi : s_criticalServiceList) { if (csi.isTimedOut()) { failure = true; s_logger.warn("Critical service " + csi.getName() + " failed -> SYSTEM REBOOT"); } } } } if (!failure) { refresh_watchdog(); } } private void refresh_watchdog() { File f = new File("/dev/watchdog"); if (f.exists()) { try { FileOutputStream fos = new FileOutputStream(f); PrintWriter pw = new PrintWriter(fos); pw.write("w"); pw.flush(); fos.getFD().sync(); pw.close(); fos.close(); } catch (IOException e) { e.printStackTrace(); } } } public boolean isConfigEnabled() { return this.m_configEnabled; } public void setConfigEnabled(boolean configEnabled) { this.m_configEnabled = configEnabled; } }