📄 locplgmgr.cpp
字号:
DEBUGCHK(g_pLocLock->IsLocked());
reportColListIter_t it = m_reportColList.begin();
reportColListIter_t itEnd = m_reportColList.end();
for (; it != itEnd; ++it) {
if (NULL != (*it)->FindRegisteredApp(pLocHandle)) {
DWORD err = UnRegisterAppForReport(pLocHandle,(*it)->GetReportType());
// Even if we don't stop the plugin, this should always succeed
// since only error cases involve bogus input (which we know is valid)
DEBUGCHK(err == ERROR_SUCCESS);
}
}
}
//*****************************************************************************
// Routines for determining relationships between plugins - especially
// with regards to whether certain plugins need to be on at a given time
//*****************************************************************************
// Get the iteration pointer to the plugin of specified start order.
pluginListIter_t pluginMgr_t::GetPluginOfStartOrder(DWORD minStartOrder) {
DEBUGCHK(minStartOrder <= (m_pluginList.size()));
if (minStartOrder == (m_pluginList.size())) {
// This indicates that we're requesting an index one past max
// number of plugins on system. This happens when the lowest priority
// plugin asks to load the next lower prio (which doesn't exist).
// To avoid sprinkling special case checks for lowestPrio plugin all over the
// place, just return iterator::end directly.
return m_pluginList.end();
}
return m_pluginList.begin() + minStartOrder;
}
// Determines if plugin is required for pReportType. See IsPluginNeeded()
// for details about when/why we call this.
BOOL pluginMgr_t::IsPluginNeededForReport(plugin_t *pPlugin, const GUID *pReportType, BOOL checkRegAppsOnly) {
// If nothing has registered for this report type, then we do not nee
DEBUGCHK(pPlugin->CanGenerateReportType(pReportType));
reportCol_t *pRC = FindRC(pReportType);
if (checkRegAppsOnly || pPlugin->IsAResolver()) {
// We only care if a user application
// has registered for this report type. We do NOT care if another resolver
// has registered for this report type because even if the pPlugin
// generated this report, the other resolver would never get it
// since resolvers don't send reports to each other.
if (! pRC->HasRegisteredApps())
return FALSE;
}
else {
// For a provider (and checkRegAppsOnly=0), either a resolver or an
// application being registered for this report type is interesting.
if (! pRC->HasRegisteredAppsOrResolvers())
return FALSE;
}
// In this case, there is some client that cares about this report
// Determine if a higher priority plugin can generate it.
BOOL highPrioPluginAvail = ExistsHigherPrioPluginForReport(pPlugin,pReportType);
if (! highPrioPluginAvail) {
// If this plugin is highest priority on the system that
// can generate this particular report type, it's still needed
// Unless...
if (pPlugin->IsAProvider() &&
IsProviderRedundantForResolvers((provider_t*)pPlugin,pReportType))
{
// ... there is a special case for providers where
// the provider may not be needed after all. See
// IsProviderRedundantForResolvers for details.
return FALSE;
}
return TRUE;
}
// If none of above conditions are met, then plugin isn't needed
// in order to generate pReportType.
return FALSE;
}
// When a plugin goes from the unavailable to available state, plugins
// of a lower priority that generate the same report should be stopped.
// This function determines if a given plugin is in such a state - namely
// are all the reports that it has been requested to generate already
// being generated by a higher priority plugin.
// This is complicated by the fact that plugins can generate multiple report
// types. Consider for instance plugin P1 that generates reports R1, R2, R3.
// Plugin P2 generates R2, R3, and R4. If P1 was asked to generate R2 but
// becomes unavailable, then P2 will be started. If P1 becomes available again,
// we would stop P2 now UNLESS another app requested report R4 to be generated.
// Since P1 doesn't generate R4, we would need to leave P2 on to do this.
BOOL pluginMgr_t::IsPluginNeeded(plugin_t *pPlugin) {
GUID generatedReports[MAX_PLUGIN_REPORT_TYPES];
DWORD numGeneratedReports;
DWORD minStartOrder = pPlugin->GetStartOrder();
DEBUGCHK(pPlugin->GetState() >= PLUGIN_STATE_SHUTTING_DOWN);
pPlugin->GetGeneratedReportInfo(generatedReports, &numGeneratedReports);
// For each possible report the plugin can generate, determine whether plugin
// needs to be left on for it.
for (DWORD i = 0; i < numGeneratedReports; i++) {
if (IsPluginNeededForReport(pPlugin,&generatedReports[i],FALSE))
return TRUE;
}
return FALSE;
}
// IsProviderRedundantForResolvers determines if provider is no longer
// required for dependent resolvers since a suitable substitute has been found.
// For instance, consider a system with Providers P1 and P2, P1 higher prio.
// P1 generates report type Rep1, P2 generates report type Rep2. Resolver Res1
// can support either R1 or R2.
// P1 was unavailable and P2 is on to service Res1. However once P1 becomes
// available again, we no longer need P2 (assuming no apps registered for Rep2)
// since P1 will generate reports for Res1.
// The base IsPluginNeeded() logic will not detect this subtle relationship
// between providers and resolvers, so we do this extra check here.
BOOL pluginMgr_t::IsProviderRedundantForResolvers(provider_t *pProv, const GUID *pReportType) {
DEBUGCHK(g_pLocLock->IsLocked());
DEBUGCHK((pProv->GetState() >= PLUGIN_STATE_UNAVAILABLE) || (pProv->GetState() == PLUGIN_STATE_ERROR));
DEBUGCHK(! ExistsHigherPrioPluginForReport(pProv,pReportType));
reportCol_t *pRC = FindRC(pReportType);
DEBUGCHK(pRC->HasRegisteredAppsOrResolvers());
if (pRC->HasRegisteredApps()) {
// If an application has registered for this report type
// and this is highest priority plugin on system that
// can generate it, then the resolver redandancy does not apply
return FALSE;
}
// For each resolver that supports this report type, see if there is an
// active provider that can generate reports for the resolver as well.
pluginListIter_t it = m_pluginList.begin();
pluginListIter_t itEnd = m_pluginList.end();
for (; it != itEnd; ++it) {
if ((*it)->IsAProvider()) {
// Only care about resolvers
continue;
}
resolver_t *pRes = (resolver_t*)((plugin_t*)(*it));
if (pRes->GetState() < PLUGIN_STATE_UNAVAILABLE) {
// If the resolver is attempting to determine location, then
// no provider is needed for it.
continue;
}
if (! pRes->CanSupportReportType(pReportType)) {
// If resolver can't generate this type anyway, then this provider
// generating it is irrelevant
continue;
}
// Now see if there is a provider of higher priority than pProv
// that is active and can generate a report the resolver supports.
// If one does not exist, then this provider is needed (hence not redundant)
if (! ExistsHigherPrioActiveProviderForResolver(pRes,pProv->GetStartOrder()))
return FALSE;
}
// For each resolver on the system that supports pReportType, we have
// verified that pProv is not needed.
return TRUE;
}
// Determines if for pReportType, whether there is a higher priority
// plugin AVAILABLE on the system to service it than pPlugin.
BOOL pluginMgr_t::ExistsHigherPrioPluginForReport(plugin_t *pPlugin, const GUID *pReportType) {
pluginListIter_t it = m_pluginList.begin();
pluginListIter_t itEnd = GetPluginOfStartOrder(pPlugin->GetStartOrder());
// Iterate through each plugin on the system, from highest prio
// until we reach the current pPlugin.
for (; it != itEnd; it++) {
if (! (*it)->CanGenerateReportType(pReportType)) {
// Plugin can't generate this report in any event.
continue;
}
PLUGIN_STATE pluginState = (*it)->GetReportTypeState(pReportType);
if (pluginState >= PLUGIN_STATE_STARTING_UP) {
// There is a higher priority plugin on the system that
// can generate this report type.
return TRUE;
}
}
// No higher priority plugin for this report found
return FALSE;
}
// Determines if there is a provider with start order < minStartOrder AND
// is active AND can generate a report that the given resolver supports.
BOOL pluginMgr_t::ExistsHigherPrioActiveProviderForResolver(resolver_t *pRes, DWORD minStartOrder) {
pluginListIter_t it = m_pluginList.begin();
pluginListIter_t itEnd = GetPluginOfStartOrder(minStartOrder);
// For each provider...
for (; it != itEnd; ++it) {
if ((*it)->IsAResolver()) {
// Only care about providers
continue;
}
if ((*it)->GetState() < PLUGIN_STATE_STARTING_UP) {
// Plugin is not active
continue;
}
GUID generatedReports[MAX_PLUGIN_REPORT_TYPES];
DWORD numGeneratedReports;
(*it)->GetGeneratedReportInfo(generatedReports, &numGeneratedReports);
for (DWORD i = 0; i < numGeneratedReports; i++) {
if (pRes->CanSupportReportType(&generatedReports[i])) {
// This resolver could be service by provider (*it).
return TRUE;
}
}
}
// No suitable providers found that can generate reports for this resolver.
return FALSE;
}
//*****************************************************************************
// Routines for starting up and stopping plugins
//*****************************************************************************
// Tries to start a particular plugin for the given reportType. This function
// verifies that the plugin can support the report type and if it can, will
// determine how to proceeed based on the current plugin state.
BOOL pluginMgr_t::StartPluginIfPossible(plugin_t *pPlugin, const GUID *pReportType) {
DEBUGCHK(g_pLocLock->IsLocked());
DEBUGCHK(g_serviceState == SERVICE_STATE_ON);
BOOL ret;
// If plugin can't even support requested type, then we're done
if (! pPlugin->CanGenerateReportType(pReportType))
return FALSE;
PLUGIN_STATE reportState = pPlugin->GetReportTypeState(pReportType);
// If this is a resolver, check its state for particular type
// against unavailable first. Resolver as a whole may be on
// but this report may already have been tried but marked unavailable.
if (pPlugin->IsAResolver() && (reportState == PLUGIN_STATE_UNAVAILABLE))
return FALSE;
// The plugin can generate this report type. How we proceed is
// based on the current state the plugin is in.
switch (pPlugin->GetState()) {
case PLUGIN_STATE_ON:
{
// If plugin is on already, then we're where we want to be.
// Explicitly (possibly redundant) register for this report in case
// this is a resolver, since resolver may be on for another report but
// not this one.
pPlugin->RequestReportGeneration(pReportType);
ret = TRUE;
}
break;
case PLUGIN_STATE_STARTING_UP:
{
// If plugin starting up, then we'll use it while realizing
// it may be some time before it's ready.
pPlugin->RequestReportGeneration(pReportType);
ret = TRUE;
}
break;
case PLUGIN_STATE_SHUTTING_DOWN:
{
// If plugin was in middle of shutdown, just let it know
// that we want to restart right away. We'll have to let the
// shutdown complete before we can do anything else, so just indicate this for now.
pPlugin->RequestReportGeneration(pReportType);
pPlugin->SetImmediateRestart();
ret = TRUE;
}
break;
case PLUGIN_STATE_ERROR:
{
// Plugin is in non-recoverable state. Nothing we can do.
ret = FALSE;
}
break;
case PLUGIN_STATE_UNAVAILABLE:
{
// Plugin is temporarily unavailable (i.e. GPS device is inside)
// then we can't start it. When the device becomes available again,
// our retry logic will stop any lower-prio plugins automatically.
pPlugin->RequestReportGeneration(pReportType);
ret = FALSE;
}
break;
case PLUGIN_STATE_OFF:
{
// Plugin is off but we want it on.
if (pPlugin->IsAProvider()) {
// For provider case, need to spin up a thread to call
// ProviderGetLocation export
provider_t *pProv = (provider_t*)pPlugin;
if (ERROR_SUCCESS != pProv->ScheduleWorkerIfNeeded())
return FALSE;
pProv->RequestReportGeneration(pReportType);
pProv->StartingUp();
ret = TRUE;
}
else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -