/*! \brief Initializes the roster. Currently only adds the registrar to the roster. The application must already be running, more precisly Run() must have been called. \return - \c B_OK: Everything went fine. - an error code */ status_t TRoster::Init() { // check lock initialization if (fLock.Sem() < 0) return fLock.Sem(); // create the info RosterAppInfo* info = new(nothrow) RosterAppInfo; if (info == NULL) return B_NO_MEMORY; // get the app's ref entry_ref ref; status_t error = get_app_ref(&ref); // init and add the info if (error == B_OK) { info->Init(be_app->Thread(), be_app->Team(), BMessenger::Private(be_app_messenger).Port(), B_EXCLUSIVE_LAUNCH | B_BACKGROUND_APP, &ref, B_REGISTRAR_SIGNATURE); info->state = APP_STATE_REGISTERED; info->registration_time = system_time(); error = AddApp(info); } if (error == B_OK) _LoadRosterSettings(); // cleanup on error if (error != B_OK) delete info; return error; }
/*! \brief Checks all registered apps for \a ref and \a signature if they are still alive, and removes those that aren't. */ void TRoster::_ValidateRunning(const entry_ref& ref, const char* signature) { while (true) { // get info via ref or signature RosterAppInfo* info = fRegisteredApps.InfoFor(&ref); if (info == NULL && signature != NULL) info = fRegisteredApps.InfoFor(signature); // if app is alive or does not exist, we can exit if (info == NULL || info->IsRunning()) return; RemoveApp(info); delete info; } }
void ShutdownProcess::_QuitApps(AppInfoList& list, bool systemApps) { PRINT(("ShutdownProcess::_QuitApps(%s)\n", (systemApps ? "system" : "user"))); if (systemApps) { _SetShutdownWindowCancelButtonEnabled(false); // check one last time for abort events uint32 event; do { team_id team; int32 phase; status_t error = _GetNextEvent(event, team, phase, false); if (error != B_OK) throw_error(error); if (event == ABORT_EVENT) { PRINT(("ShutdownProcess::_QuitApps(): shutdown cancelled by " "team %ld (-1 => user)\n", team)); _DisplayAbortingApp(team); throw_error(B_SHUTDOWN_CANCELLED); } } while (event != NO_EVENT); } // prepare the shutdown message BMessage message; _PrepareShutdownMessage(message); // now iterate through the list of apps while (true) { // eat events uint32 event; do { team_id team; int32 phase; status_t error = _GetNextEvent(event, team, phase, false); if (error != B_OK) throw_error(error); if (!systemApps && event == ABORT_EVENT) { PRINT(("ShutdownProcess::_QuitApps(): shutdown cancelled by " "team %ld (-1 => user)\n", team)); _DisplayAbortingApp(team); throw_error(B_SHUTDOWN_CANCELLED); } } while (event != NO_EVENT); // get the first app to quit team_id team = -1; port_id port = -1; char appName[B_FILE_NAME_LENGTH]; { BAutolock _(fWorkerLock); while (!list.IsEmpty()) { RosterAppInfo* info = *list.It(); team = info->team; port = info->port; strcpy(appName, info->ref.name); if (info->IsRunning()) break; list.RemoveInfo(info); delete info; } } if (team < 0) { PRINT(("ShutdownProcess::_QuitApps() done\n")); return; } // set window text BString buffer = B_TRANSLATE("Asking \"%appName%\" to quit."); buffer.ReplaceFirst("%appName%", appName); _SetShutdownWindowText(buffer.String()); _SetShutdownWindowCurrentApp(team); // send the shutdown message to the app PRINT((" sending team %ld (port: %ld) a shutdown message\n", team, port)); SingleMessagingTargetSet target(port, B_PREFERRED_TOKEN); MessageDeliverer::Default()->DeliverMessage(&message, target); // schedule a timeout event _ScheduleTimeoutEvent(kAppQuitTimeout, team); // wait for the app to die or for the timeout to occur bool appGone = _WaitForApp(team, &list, systemApps); if (appGone) { // fine: the app finished in an orderly manner } else { // the app is either blocking on a model alert or blocks for another // reason if (!systemApps) _QuitBlockingApp(list, team, appName, true); else { // This is a system app: remove it from the list BAutolock _(fWorkerLock); if (RosterAppInfo* info = list.InfoFor(team)) { list.RemoveInfo(info); delete info; } } } } }
/*! \brief Handles an AddApplication() request. \param request The request message */ void TRoster::HandleAddApplication(BMessage* request) { FUNCTION_START(); BAutolock _(fLock); status_t error = B_OK; // get the parameters const char* signature; entry_ref ref; uint32 flags; team_id team; thread_id thread; port_id port; bool fullReg; if (request->FindString("signature", &signature) != B_OK) signature = NULL; if (request->FindRef("ref", &ref) != B_OK) SET_ERROR(error, B_BAD_VALUE); if (request->FindInt32("flags", (int32*)&flags) != B_OK) flags = B_REG_DEFAULT_APP_FLAGS; if (request->FindInt32("team", &team) != B_OK) team = -1; if (request->FindInt32("thread", &thread) != B_OK) thread = -1; if (request->FindInt32("port", &port) != B_OK) port = -1; if (request->FindBool("full_registration", &fullReg) != B_OK) fullReg = false; PRINT("team: %" B_PRId32 ", signature: %s\n", team, signature); PRINT("full registration: %d\n", fullReg); if (fShuttingDown) error = B_SHUTTING_DOWN; // check the parameters team_id otherTeam = -1; uint32 token = 0; uint32 launchFlags = flags & B_LAUNCH_MASK; BEntry entry(&ref); if (!entry.Exists()) SET_ERROR(error, B_ENTRY_NOT_FOUND); if (error == B_OK) _ValidateRunning(ref, signature); // entry_ref if (error == B_OK) { PRINT("flags: %" B_PRIx32 "\n", flags); PRINT("ref: %" B_PRId32 ", %" B_PRId64 ", %s\n", ref.device, ref.directory, ref.name); // check single/exclusive launchers RosterAppInfo* info = NULL; if ((launchFlags == B_SINGLE_LAUNCH || launchFlags == B_EXCLUSIVE_LAUNCH) && ((info = fRegisteredApps.InfoFor(&ref)) != NULL || (info = fEarlyPreRegisteredApps.InfoFor(&ref)) != NULL)) { SET_ERROR(error, B_ALREADY_RUNNING); otherTeam = info->team; token = info->token; } } // signature if (error == B_OK && signature) { // check exclusive launchers RosterAppInfo* info = NULL; if (launchFlags == B_EXCLUSIVE_LAUNCH && (((info = fRegisteredApps.InfoFor(signature))) || ((info = fEarlyPreRegisteredApps.InfoFor(signature))))) { SET_ERROR(error, B_ALREADY_RUNNING); otherTeam = info->team; token = info->token; } } // If no team ID is given, full registration isn't possible. if (error == B_OK) { if (team < 0) { if (fullReg) SET_ERROR(error, B_BAD_VALUE); } else if (fRegisteredApps.InfoFor(team)) SET_ERROR(error, B_REG_ALREADY_REGISTERED); } // Add the application info. if (error == B_OK) { // alloc and init the info RosterAppInfo* info = new(nothrow) RosterAppInfo; if (info) { info->Init(thread, team, port, flags, &ref, signature); if (fullReg) info->state = APP_STATE_REGISTERED; else info->state = APP_STATE_PRE_REGISTERED; info->registration_time = system_time(); // add it to the right list bool addingSuccess = false; if (team >= 0) { PRINT("added ref: %" B_PRId32 ", %" B_PRId64 ", %s\n", info->ref.device, info->ref.directory, info->ref.name); addingSuccess = (AddApp(info) == B_OK); if (addingSuccess && fullReg) _AppAdded(info); } else { token = info->token = _NextToken(); addingSuccess = fEarlyPreRegisteredApps.AddInfo(info); PRINT("added to early pre-regs, token: %" B_PRIu32 "\n", token); } if (!addingSuccess) SET_ERROR(error, B_NO_MEMORY); } else SET_ERROR(error, B_NO_MEMORY); // delete the info on failure if (error != B_OK && info) delete info; } // reply to the request if (error == B_OK) { // add to recent apps if successful if (signature && signature[0] != '\0') fRecentApps.Add(signature, flags); else fRecentApps.Add(&ref, flags); BMessage reply(B_REG_SUCCESS); // The token is valid only when no team ID has been supplied. if (team < 0) reply.AddInt32("token", (int32)token); request->SendReply(&reply); } else { BMessage reply(B_REG_ERROR); reply.AddInt32("error", error); if (otherTeam >= 0) reply.AddInt32("other_team", otherTeam); if (token > 0) reply.AddInt32("token", (int32)token); request->SendReply(&reply); } FUNCTION_END(); }
/*! \brief Returns lists of applications to be asked to quit on shutdown. \param userApps List of RosterAppInfos identifying the user applications. Those will be ask to quit first. \param systemApps List of RosterAppInfos identifying the system applications (like Tracker and Deskbar), which will be asked to quit after the user applications are gone. \param vitalSystemApps A set of team_ids identifying teams that must not be terminated (app server and registrar). \return \c B_OK, if everything went fine, another error code otherwise. */ status_t TRoster::GetShutdownApps(AppInfoList& userApps, AppInfoList& systemApps, AppInfoList& backgroundApps, hash_set<team_id>& vitalSystemApps) { BAutolock _(fLock); status_t error = B_OK; // get the vital system apps: // * ourself // * kernel team // * app server // * debug server // ourself vitalSystemApps.insert(be_app->Team()); // kernel team team_info teamInfo; if (get_team_info(B_SYSTEM_TEAM, &teamInfo) == B_OK) vitalSystemApps.insert(teamInfo.team); // app server RosterAppInfo* info = fRegisteredApps.InfoFor("application/x-vnd.haiku-app_server"); if (info != NULL) vitalSystemApps.insert(info->team); // debug server info = fRegisteredApps.InfoFor("application/x-vnd.haiku-debug_server"); if (info != NULL) vitalSystemApps.insert(info->team); // populate the other groups for (AppInfoList::Iterator it(fRegisteredApps.It()); RosterAppInfo* info = *it; ++it) { if (vitalSystemApps.find(info->team) == vitalSystemApps.end()) { RosterAppInfo* clonedInfo = info->Clone(); if (clonedInfo) { if (_IsSystemApp(info)) { if (!systemApps.AddInfo(clonedInfo)) error = B_NO_MEMORY; } else if (info->flags & B_BACKGROUND_APP) { if (!backgroundApps.AddInfo(clonedInfo)) error = B_NO_MEMORY; } else { if (!userApps.AddInfo(clonedInfo)) error = B_NO_MEMORY; } if (error != B_OK) delete clonedInfo; } else error = B_NO_MEMORY; } if (error != B_OK) break; } // Special case, we add the input server to vital apps here so it is // not excluded in the lists above info = fRegisteredApps.InfoFor("application/x-vnd.Be-input_server"); if (info != NULL) vitalSystemApps.insert(info->team); // clean up on error if (error != B_OK) { userApps.MakeEmpty(true); systemApps.MakeEmpty(true); } return error; }