main.cpp

Go to the documentation of this file.
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