1 /* 2 * Copyright 2002, Marcus Overhagen. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <OS.h> 7 #include <Application.h> 8 #include <Roster.h> 9 #include <Directory.h> 10 #include <Entry.h> 11 #include <Messenger.h> 12 #include <Autolock.h> 13 #include <stdio.h> 14 #include "debug.h" 15 #include "AppManager.h" 16 #include "NodeManager.h" 17 #include "BufferManager.h" 18 #include "NotificationManager.h" 19 #include "media_server.h" 20 21 AppManager::AppManager() 22 : fAddonServer(-1) 23 { 24 fAppMap = new Map<team_id, App>; 25 fLocker = new BLocker("app manager locker"); 26 fQuit = create_sem(0, "big brother waits"); 27 fBigBrother = spawn_thread(bigbrother, "big brother is watching you", B_NORMAL_PRIORITY, this); 28 resume_thread(fBigBrother); 29 } 30 31 AppManager::~AppManager() 32 { 33 status_t err; 34 delete_sem(fQuit); 35 wait_for_thread(fBigBrother, &err); 36 delete fLocker; 37 delete fAppMap; 38 } 39 40 bool AppManager::HasTeam(team_id team) 41 { 42 BAutolock lock(fLocker); 43 return fAppMap->Has(team); 44 } 45 46 status_t AppManager::RegisterTeam(team_id team, BMessenger messenger) 47 { 48 BAutolock lock(fLocker); 49 TRACE("AppManager::RegisterTeam %ld\n", team); 50 if (HasTeam(team)) { 51 FATAL("Erorr: AppManager::RegisterTeam: team %ld already registered\n", team); 52 return B_ERROR; 53 } 54 App app; 55 app.team = team; 56 app.messenger = messenger; 57 return fAppMap->Insert(team, app) ? B_OK : B_ERROR; 58 } 59 60 status_t AppManager::UnregisterTeam(team_id team) 61 { 62 bool is_removed; 63 bool is_addon_server; 64 65 TRACE("AppManager::UnregisterTeam %ld\n", team); 66 67 fLocker->Lock(); 68 is_removed = fAppMap->Remove(team); 69 is_addon_server = fAddonServer == team; 70 if (is_addon_server) 71 fAddonServer = -1; 72 fLocker->Unlock(); 73 74 CleanupTeam(team); 75 if (is_addon_server) 76 CleanupAddonServer(); 77 78 return is_removed ? B_OK : B_ERROR; 79 } 80 81 void AppManager::RestartAddonServer() 82 { 83 static bigtime_t restart_period = 0; 84 static int restart_tries = 0; 85 restart_tries++; 86 87 if (((system_time() - restart_period) > 60000000LL) && (restart_tries < 5)) { 88 restart_period = system_time(); 89 restart_tries = 0; 90 } 91 if (restart_tries < 5) { 92 FATAL("AppManager: Restarting media_addon_server...\n"); 93 // XXX fixme. We should wait until it is *really* gone 94 snooze(5000000); 95 StartAddonServer(); 96 } else { 97 FATAL("AppManager: media_addon_server crashed too often, not restarted\n"); 98 } 99 } 100 101 102 void AppManager::TeamDied(team_id team) 103 { 104 CleanupTeam(team); 105 fLocker->Lock(); 106 fAppMap->Remove(team); 107 fLocker->Unlock(); 108 } 109 110 status_t AppManager::RegisterAddonServer(team_id team) 111 { 112 BAutolock lock(fLocker); 113 if (fAddonServer != -1) 114 return B_ERROR; 115 fAddonServer = team; 116 return B_OK; 117 } 118 119 //========================================================================= 120 // The BigBrother thread send ping messages to the BMediaRoster of 121 // all currently running teams. If the reply times out or is wrong, 122 // the team cleanup function TeamDied() will be called. If the dead 123 // team is the media_addon_server, additionally CleanupAddonServer() 124 // will be called and also RestartAddonServer() 125 //========================================================================= 126 127 int32 AppManager::bigbrother(void *self) 128 { 129 static_cast<AppManager *>(self)->BigBrother(); 130 return 0; 131 } 132 133 void AppManager::BigBrother() 134 { 135 bool restart_addon_server; 136 status_t status; 137 BMessage msg('PING'); 138 BMessage reply; 139 team_id team; 140 App *app; 141 do { 142 if (!fLocker->Lock()) 143 break; 144 for (fAppMap->Rewind(); fAppMap->GetNext(&app); ) { 145 reply.what = 0; 146 status = app->messenger.SendMessage(&msg, &reply, 5000000, 2000000); 147 if (status != B_OK || reply.what != 'PONG') { 148 team = app->team; 149 if (fAddonServer == team) { 150 restart_addon_server = true; 151 fAddonServer = -1; 152 } else { 153 restart_addon_server = false; 154 } 155 fLocker->Unlock(); 156 TeamDied(team); 157 if (restart_addon_server) { 158 CleanupAddonServer(); 159 RestartAddonServer(); 160 } 161 continue; 162 } 163 } 164 fLocker->Unlock(); 165 status = acquire_sem_etc(fQuit, 1, B_RELATIVE_TIMEOUT, 2000000); 166 } while (status == B_TIMED_OUT || status == B_INTERRUPTED); 167 } 168 169 //========================================================================= 170 // The following functions must be called unlocked. 171 // They clean up after a crash, or start/terminate the media_addon_server. 172 //========================================================================= 173 174 void AppManager::CleanupTeam(team_id team) 175 { 176 ASSERT(false == fLocker->IsLocked()); 177 178 TRACE("AppManager: cleaning up team %ld\n", team); 179 180 gNodeManager->CleanupTeam(team); 181 gBufferManager->CleanupTeam(team); 182 gNotificationManager->CleanupTeam(team); 183 } 184 185 void AppManager::CleanupAddonServer() 186 { 187 ASSERT(false == fLocker->IsLocked()); 188 189 TRACE("AppManager: cleaning up media_addon_server\n"); 190 191 } 192 193 void AppManager::StartAddonServer() 194 { 195 ASSERT(false == fLocker->IsLocked()); 196 197 app_info info; 198 be_app->GetAppInfo(&info); 199 BEntry entry(&info.ref); 200 entry.GetParent(&entry); 201 BDirectory dir(&entry); 202 entry.SetTo(&dir, "media_addon_server"); 203 entry_ref ref; 204 entry.GetRef(&ref); 205 be_roster->Launch(&ref); 206 } 207 208 void AppManager::TerminateAddonServer() 209 { 210 ASSERT(false == fLocker->IsLocked()); 211 212 if (fAddonServer != -1) { 213 BMessenger msger(NULL, fAddonServer); 214 msger.SendMessage(B_QUIT_REQUESTED); 215 // XXX fixme. We should wait until it is gone 216 snooze(1000000); 217 } 218 } 219