00001 /* 00002 00003 Copyright (C) 2004 Mika Raento - Renaud Petit 00004 email: mraento@cs.helsinki.fi - petit@cs.helsinki.fi 00005 00006 Copyright 2008 Helsinki Institute for Information Technology (HIIT) 00007 and Tero Hasu <tero.hasu@hut.fi>. All rights reserved. 00008 00009 This license applies: 00010 00011 This program is free software; you can redistribute it and/or modify 00012 it under the terms of the GNU General Public License as published by 00013 the Free Software Foundation; either version 2 of the License, or 00014 (at your option) any later version. 00015 00016 This program is distributed in the hope that it will be useful, 00017 but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 GNU General Public License for more details. 00020 00021 You should have received a copy of the GNU General Public License 00022 along with this program; if not, write to the Free Software 00023 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00024 00025 Alternatively, this license applies: 00026 00027 Permission is hereby granted, free of charge, to any person 00028 obtaining a copy of this software and associated documentation files 00029 (the "Software"), to deal in the Software without restriction, 00030 including without limitation the rights to use, copy, modify, merge, 00031 publish, distribute, sublicense, and/or sell copies of the Software, 00032 and to permit persons to whom the Software is furnished to do so, 00033 subject to the following conditions: 00034 00035 The above copyright notice and this permission notice shall be 00036 included in all copies or substantial portions of the Software. 00037 00038 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 00039 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00040 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00041 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 00042 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 00043 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 00044 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 00045 SOFTWARE. 00046 00047 Design: 00048 00049 We try to keep this module as small and free of dependencies as 00050 possible. Hence no Open C or anything but Symbian native stuff here. 00051 The whole thing is highly Symbian specific anyway. 00052 00053 We basically want to start a specific executable, and observe it. If 00054 it dies, we attempt a restart after a little while; if it dies 00055 quickly, increase the retry time interval; when system memory is very 00056 low, do not even attempt a restart, but just reschedule. 00057 00058 We shall do some minimal logging or failures, but in release builds 00059 the log must not grow indefinitely. Presently we have none in release 00060 builds, and indefinitely growing (per runtime) in debug builds. 00061 (Ideally we would check the file size to make sure that the log size 00062 stays reasonable, and make it so that when the size limit is exceeded, 00063 halve the size, keeping the latest entries only. But probably simpler 00064 to just have the latest entry in the log, or, more generally, to 00065 always clear the log after N entries.) 00066 00067 Details: 00068 00069 * Wait for a little while before doing anything, to hopefully ensure 00070 that the system is somewhat up and running. Typically, after all, the 00071 watchdog would be started at boot. 00072 00073 * Check if there is a magic file whose existence indicates there 00074 should be no autostarting; if so, then die. 00075 00076 * Check if the application to launch is installed; if it is not, 00077 then die, as there is little hope of launching something that does not 00078 exist. 00079 00080 * Check if the application is already running by looking at the task 00081 list. If it is, then get a handle to its main thread, and observe it 00082 using Logon. If it is not, then start it. 00083 00084 * Wait for a little while, and see if the application is running. If 00085 so, log that. If not, wait a bit longer, and keep checking. If still 00086 not running log this fact, and set a fairly long retry period. If runs 00087 but not for long, log that too, and again set a fairly long retry 00088 period. We do not want to end up busy looping here. 00089 00090 To allow for possible client-server framework use, we shall be using 00091 active objects to implement the watchdog logic. A timer and logon AO 00092 should be just about enough here. We are presently not using the 00093 client-server framework, but AOfication should also be useful for 00094 testing, say when embedding the watchdog into a GUI app. 00095 00096 Nice to have would be (we presently do not): An in-memory log that 00097 retains a number of recent entries, and such that CL2 can query for 00098 those entries once running. Any entries served to a client should be 00099 automatically deleted. Old entries not queried fast enough shall also 00100 be deleted. 00101 00102 */ 00103 00104 #include "watchdog.h" 00105 00106 #include "common/epoc_app_uid_list.hrh" 00107 #include "common/epoc-utilities.hpp" 00108 #include "common/logging.h" 00109 #include "common/panic.h" 00110 00111 #include <e32std.h> 00112 #include <apgcli.h> 00113 #include <bautils.h> 00114 00115 // We could consider having CActiveSchedulerWait owned by the watchdog 00116 // object, as then the watchdog itself could implement a Loop method; 00117 // no one else really uses CActiveSchedulerWait anyway. 00118 void MainLoopL() 00119 { 00120 CActiveSchedulerWait* loop = new (ELeave) CActiveSchedulerWait; 00121 CleanupStack::PushL(loop); 00122 // The watchdog will be running after its initialization. In error 00123 // situations it will invoke AsyncStop() on the passed loop. 00124 CWatchdog* watchdog = CWatchdog::NewLC(*loop); 00125 watchdog->Start(); 00126 // AsyncStop will cause an exit from the loop, but we only want to 00127 // invoke AsyncStop in severe error situations. This means that if 00128 // Start() does return, then there must have been an error. 00129 loop->Start(); 00130 CleanupStack::PopAndDestroy(watchdog); 00131 CleanupStack::PopAndDestroy(loop); 00132 } 00133 00134 // This only works for applications, not your plain EXEs. 00135 static TBool IsAppInstalledL() 00136 { 00137 #if 1 00138 return ETrue; 00139 #else 00140 TBool result; 00141 RApaLsSession ls; 00142 User::LeaveIfError(ls.Connect()); 00143 CleanupClosePushL(ls); 00144 TApaAppInfo appInfo; 00145 // Note that this returns false for applications which have not been 00146 // installed using a SIS file. 00147 TInt errCode = ls.GetAppInfo(appInfo, TUid::Uid(APP_UID_CL2_LOGGER_DAEMON)); 00148 if (errCode == KErrNotFound) 00149 result = EFalse; 00150 else if (errCode) 00151 User::Leave(errCode); 00152 else 00153 result = ETrue; 00154 CleanupStack::PopAndDestroy(); // ls 00155 return result; 00156 #endif 00157 } 00158 00159 static TBool MagicFileExists(RFs& fs) 00160 { 00161 _LIT(KFile, "c:\\data\\cl2\\disable_autostart.txt"); 00162 TBool res = BaflUtils::FileExists(fs, KFile); 00163 return res; 00164 } 00165 00166 static void WaitWhile() 00167 { 00168 User::After(TTimeIntervalMicroSeconds32(7 * 1000000)); 00169 } 00170 00171 static void MainL() 00172 { 00173 log_clear(PRIMARY_LOG_FILENAME); 00174 log_text(PRIMARY_LOG_FILENAME, "initializing"); 00175 logg("value is %d", 555); 00176 log_ctx(PRIMARY_LOG_FILENAME, "context test"); 00177 00178 // Note that if our program does not run for at least five seconds 00179 // or so, the S60 auto launch mechanism will consider that an error, 00180 // and this may result in some error dialog popping up. We use 00181 // WaitWhile() to avoid that sort of thing where an intrusive error 00182 // report is not called for. Calling WaitWhile will hopefully also 00183 // ensure that the system is somewhat up and running even right after 00184 // boot, so that there are no problems with querying the installed 00185 // apps information or anything like that. 00186 WaitWhile(); 00187 00188 RFs fs; 00189 User::LeaveIfError(fs.Connect()); 00190 CleanupClosePushL(fs); 00191 00192 TBool magicFileExists = MagicFileExists(fs); 00193 if (!magicFileExists) { 00194 TBool isAppInstalled = IsAppInstalledL(); 00195 if (isAppInstalled) { 00196 MainLoopL(); 00197 } else { 00198 logt("program to launch not installed"); 00199 } 00200 } else { 00201 logt("magic file exists"); 00202 } 00203 00204 CleanupStack::PopAndDestroy(); // fs 00205 } 00206 00207 // Once this function gets invoked, the S60 autostart system should 00208 // have seen to it that the system is already up and running. We may 00209 // not want to hurry with launching anything else, however, as the 00210 // system may still be somewhat busy right after (or in the later 00211 // stages of) boot. 00212 GLDEF_C TInt E32Main() 00213 { 00214 int errCode = 0; 00215 __UHEAP_MARK; 00216 WITH_CLEANUP_STACK_ERR(errCode, 00217 WITH_ACTIVE_SCHEDULER_ERR(errCode, 00218 TRAP(errCode, MainL()); 00219 ); 00220 ); 00221 __UHEAP_MARKEND; 00222 // xxx would like some way of logging error exit information in 00223 // non-debug builds also, here and elsewhere, but so that logs 00224 // cannot grow indefinitely; this means that we can should compile 00225 // in logging.cpp even when your usual logging is disabled; sounds 00226 // like we require another compilation option, and maybe some more 00227 // macros like log_always or somesuch 00228 return errCode; 00229 }
ContextLogger2—ContextLogger2 Logger Daemon Internals—Generated on Mon May 2 13:49:55 2011 by Doxygen 1.6.1