📄 loccore.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
// Abstract: Location framework core logic
#include <locCore.hpp>
//
// Location framework debug info
//
#if defined(UNDER_CE) && defined (DEBUG)
DBGPARAM dpCurSettings = {
TEXT("LFSVC"), {
TEXT("Init"),TEXT("Service"),TEXT("Provider"),TEXT("Resolver"),
TEXT("Report Collector"),TEXT("Plugin Mgr"),TEXT("API"),TEXT("Thread"),
TEXT(""),TEXT(""),TEXT(""),TEXT("Verbose"),
TEXT("Alloc"),TEXT("Function"),TEXT("Error"),TEXT("Warn") },
0xC000
};
#endif
//
// Define registry key and value constants
//
const WCHAR *g_rkLocBase = L"System\\CurrentControlSet\\Location Framework";
const WCHAR *g_rkProviders = L"Providers";
const WCHAR *g_rkResolvers = L"Resolvers";
const WCHAR *g_rvDll = L"DLL";
const WCHAR *g_rvFriendlyName = L"FriendlyName";
const WCHAR *g_rvGuid = L"GUID";
const WCHAR *g_rvPreference = L"Preference";
const WCHAR *g_rvPluginFlags = L"PluginFlags";
const WCHAR *g_rvVersion = L"Version";
const WCHAR *g_rvProviderFlags = L"ProviderFlags";
const WCHAR *g_rvResolverFlags = L"ResolverFlags";
const WCHAR *g_rvPollInterval = L"PollInterval";
const WCHAR *g_rvRetryOnFailure = L"RetryOnFailure";
const WCHAR *g_rvMaximumInitialWait = L"MaximumInitialWait";
const WCHAR *g_rvGeneratedReports = L"GeneratedReports";
const WCHAR *g_rvSupportedReports = L"SupportedReports";
const WCHAR *g_rvMinimumRequery = L"MinimumRequery";
//
// Global variables
//
// Global lock
SVSSynch *g_pLocLock;
// Thread pool
SVSThreadPool *g_pThreadPool;
// Current service state of location framework (from service.h)
DWORD g_serviceState;
// Maps handles between application layer and this service
handleMgr_t *g_pHandleMgr;
// Wait this many milliseconds on each poll to see if we can unload LF.
const DWORD g_pollOnUnload = 100;
// When trying to unload, if we have to go into a wait loop > 50 times, DEBUGCHK
const DWORD g_pollRetriesWarnOnUnload = 50;
// Maximum number of simultaneous worker threads for location framework.
static const DWORD g_maxWorkerThreads = 40;
//
// Startup and shutdown related functionality
//
// Initializes service. Only called once from DllMain(). All functions
// called here MUST be DllMain safe.
BOOL InitLocService(void) {
// Init global critical section, other truly global stuff...
svsutil_Initialize();
g_pLocLock = new SVSSynch();
if (g_pLocLock == NULL) {
DEBUGMSG_OOM();
return FALSE;
}
g_pHandleMgr = new handleMgr_t();
if ((g_pHandleMgr == NULL) || (!g_pHandleMgr->IsHandleMgrInited())) {
DEBUGMSG_OOM();
return FALSE;
}
g_pThreadPool = new SVSThreadPool(g_maxWorkerThreads);
if (g_pThreadPool == NULL) {
DEBUGMSG_OOM();
delete g_pLocLock;
return FALSE;
}
g_serviceState = SERVICE_STATE_UNINITIALIZED;
return TRUE;
}
// DeInitializes service. Only called once from DllMain(). Make sure
// everything is DllMain safe.
void DeInitLocService(void) {
DEBUGCHK(g_serviceState == SERVICE_STATE_UNLOADING);
#ifdef SVSUTIL_DEBUG_THREADS
// DEBUG verify that that threadpool has no running threads.
// This function is called from DllMain() where we must not block
SVS_THREAD_POOL_STATS threadPoolStats;
g_pThreadPool->GetStatistics(&threadPoolStats);
DEBUGCHK(threadPoolStats.cThreadsRunning == 0);
#endif
if (g_pThreadPool) {
delete g_pThreadPool;
g_pThreadPool = NULL;
}
if (g_pHandleMgr) {
delete g_pHandleMgr;
g_pHandleMgr = NULL;
}
if (g_pLocLock) {
delete g_pLocLock;
g_pLocLock = NULL;
}
svsutil_DeInitialize();
}
// Frees globals that are created/destroyed when service is stopped/started
// (but not loaded or unloaded).
void FreeLocGlobals() {
DEBUGCHK(g_pLocLock->IsLocked());
DEBUGCHK((g_serviceState != SERVICE_STATE_ON) && (g_serviceState != SERVICE_STATE_STARTING_UP));
// Need to clear out any existing handles at this stage, but do NOT
// delete this object since we still need it to process LOC_Open()
// service handles
g_pHandleMgr->ResetLocHandles();
if (g_pPluginMgr) {
delete g_pPluginMgr;
g_pPluginMgr = NULL;
}
}
// Takes service from stopped->on state
static DWORD StartLocService(BOOL firstStartup) {
DEBUGMSG(ZONE_INIT,(L"LOC: Starting Location Framework Service\r\n"));
DEBUGCHK(g_pLocLock->IsLocked());
DWORD err;
if (! firstStartup) {
// The first time we're started, state=SERVICE_STATE_STARTING_UP.
// After that, we need to verify we're not already on or shutting down
// or whatever before begining service startup.
if (g_serviceState != SERVICE_STATE_OFF) {
DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: Starting service fails because service state must be off, but is instead <%d>\r\n",g_serviceState));
err = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
// Do not cleanup global state in this case.
goto doneNoCleanup;
}
g_serviceState = SERVICE_STATE_STARTING_UP;
}
DEBUGCHK(g_serviceState == SERVICE_STATE_STARTING_UP);
//
// Initialize global objects
//
g_pPluginMgr = new pluginMgr_t();
if (g_pPluginMgr == NULL) {
DEBUGMSG_OOM();
err = ERROR_OUTOFMEMORY;
goto done;
}
if (! g_pPluginMgr->IsPlgMgrInited()) {
// Init normally fails because of some misconfiguration in the system
// such as the LF registry key not being present.
err = ERROR_INTERNAL_ERROR;
goto done;
}
err = ERROR_SUCCESS;
g_serviceState = SERVICE_STATE_ON;
done:
if (err != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: Starting location service failed. Error=0x%08x\r\n",err));
g_serviceState = SERVICE_STATE_OFF;
FreeLocGlobals();
}
else
DEBUGMSG(ZONE_INIT,(L"LOC: Location Framework Service started successfully\r\n"));
doneNoCleanup:
return err;
}
// Do real work of stopping and starting location framework on a worker
// thread because some plugins may do unsafe operations on PSL thread
// of caller (in particular COM + TLS)
DWORD WINAPI StartLocServiceThread(LPVOID lpv) {
g_pLocLock->Lock();
DWORD err = StartLocService((BOOL)lpv);
DEBUGCHK(g_serviceState==SERVICE_STATE_ON || g_serviceState==SERVICE_STATE_OFF);
g_pLocLock->Unlock();
return err;
}
// Takes service from the running state->off/unloading state
static DWORD StopLocService(BOOL unloadService) {
DEBUGMSG(ZONE_INIT,(L"LOC: Stopping Location Framework Service\r\n"));
DEBUGCHK(g_pLocLock->IsLocked());
DWORD err;
if (unloadService) {
// When service is requested to unload, then we MUST block until
// service can be unloaded (and particular until worker threads are stopped)
// If service was starting up or shutting down already, wait until it is complete
// before continuing with shutdown
#ifdef DEBUG
// If it takes more than 20 cycles through loop below to get into a steady
// state, then something is likely wrong with LF.
DWORD pollAttempts = 0;
#endif
while ((g_serviceState != SERVICE_STATE_ON) && (g_serviceState != SERVICE_STATE_OFF)) {
#ifdef DEBUG
pollAttempts++;
DEBUGCHK(g_pollRetriesWarnOnUnload != pollAttempts);
#endif
g_pLocLock->Unlock();
DEBUGMSG(ZONE_SERVICE,(L"LF: Sleeping <%d> ms on LF unload, waiting to be in state off or state on\r\n",g_pollOnUnload));
Sleep(g_pollOnUnload);
g_pLocLock->Lock();
}
}
else {
// If service is not being unloaded but just stopped (i.e. IOCTL_SERVICE_STOP),
// then service must be ON in order to proceed.
if (g_serviceState != SERVICE_STATE_ON) {
DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: Attempt to stop service fails since state is not ON, state is <%d>\r\n",g_serviceState));
err = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
goto done;
}
}
g_serviceState = unloadService ? SERVICE_STATE_UNLOADING : SERVICE_STATE_SHUTTING_DOWN;
FreeLocGlobals();
#ifdef SVSUTIL_DEBUG_THREADS
// DEBUG verify that that threadpool has no running threads.
// Deleting g_pPluginMgr should wait until all workers have stopped.
SVS_THREAD_POOL_STATS threadPoolStats;
g_pThreadPool->GetStatistics(&threadPoolStats);
DEBUGCHK(threadPoolStats.cThreadsRunning == 0);
#endif
// The thread pool may have idle worker threads still available.
// Make these close down now also. This is needed because on a service
// DeInit(), the thread pool will try to destroy these threads which
// can lead to deadlock should we be trying this in DllMain().
g_pThreadPool->Shutdown();
g_pThreadPool->Reset();
if (!unloadService)
g_serviceState = SERVICE_STATE_OFF;
err = ERROR_SUCCESS;
done:
return err;
}
// Stop location framework on a worker thread in services.exe --
// see StartLocServiceThread comments
DWORD WINAPI StopLocServiceThread(LPVOID lpv) {
g_pLocLock->Lock();
DWORD err = StopLocService((BOOL)lpv);
#ifdef DEBUG
if (lpv) { // unloading service
DEBUGCHK(g_serviceState==SERVICE_STATE_UNLOADING);
}
else {
DEBUGCHK(g_serviceState==SERVICE_STATE_ON || g_serviceState==SERVICE_STATE_OFF);
}
#endif
g_pLocLock->Unlock();
return err;
}
// Refresh location framework on a worker thread in services.exe --
// see StartLocServiceThread comments
DWORD WINAPI RefreshLocServiceThread(LPVOID lpv) {
g_pLocLock->Lock();
DEBUGMSG(ZONE_INIT,(L"LOC: Refreshing Location Framework Service\r\n"));
DWORD err = StopLocService(FALSE);
if (err == ERROR_SUCCESS)
err = StartLocService(FALSE);
g_pLocLock->Unlock();
return err;
}
// Spin up a thread with the specified function, blocking until it has completed.
BOOL LocationSpinThreadAndWait(PFN_LOCATION_THREAD pFunc, LPVOID lpv) {
DEBUGCHK(! g_pLocLock->IsLocked());
HANDLE hThread = CreateThread(NULL,0,pFunc,lpv,0,NULL);
if (! hThread) {
DEBUGMSG(ZONE_ERROR,(L"LOCATION: CreateThread failed, GLE=<0x%08x>\r\n",GetLastError()));
return ERROR_OUTOFMEMORY;
}
DWORD err;
WaitForSingleObject(hThread,INFINITE);
if (! GetExitCodeThread(hThread,&err)) {
DEBUGMSG(ZONE_ERROR,(L"LOCATION: GetExitCodeThread failed, GLE=<0x%08x>\r\n",GetLastError()));
DEBUGCHK(0); // Something is seriously wrong with system or services.exe itself
err = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
}
if (err != ERROR_SUCCESS)
SetLastError(err);
CloseHandle(hThread);
return (err==ERROR_SUCCESS);
}
// Implements IOCTL_SERVICE_STATUS processing.
BOOL GetServiceStatus(PBYTE pBufOut, DWORD lenOut, DWORD *pActualLenOut) {
DEBUGCHK(g_pLocLock->IsLocked());
if (!pBufOut || lenOut < sizeof(DWORD)) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
__try {
*(DWORD *)pBufOut = g_serviceState;
if (pActualLenOut)
*pActualLenOut = sizeof(DWORD);
}
__except (REPORT_EXCEPTION_TO_WATSON()) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return TRUE;
}
//
// Handeling of user mode APIs calls
//
BOOL LocationOpenIntrnl(
serviceHandle_t *pServiceHandle,
DWORD version,
ce::PSL_HANDLE pReserved, // No PSL marshalling of pReserved since it's only checked vs NULL
DWORD flags,
ce::marshal_arg<ce::copy_out,ce::PSL_HANDLE *> phOutHandle
)
{
DEBUGMSG(ZONE_API,(L"LOC: LocationOpen(0x%08x,0x%08x,0x%08x) called\r\n",version,pReserved,flags));
DEBUGCHK(g_pLocLock->IsLocked());
if (version != LOCATION_FRAMEWORK_VERSION_1) {
DEBUGMSG(ZONE_ERROR,(L"LOC: LocationOpen() failed because version = <%d>, not required <%d>\r\n",version,LOCATION_FRAMEWORK_VERSION_1));
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if ((pReserved != 0) || (flags != 0)) {
// pReserved is a PSL_HANDLE because a VOID* because certain VOID* non-NULL vals may get
// marshalled as NULL by the PSL marshaller templates.
DEBUGMSG(ZONE_ERROR,(L"LOC: LocationOpen() failed because pReserved and/or flags are defined\r\n"));
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (phOutHandle == NULL) {
DEBUGMSG(ZONE_ERROR,(L"LOC: LocationOpen() failed because phOutHandle is NULL\r\n"));
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
HLOCATION h = g_pHandleMgr->AllocLocationHandle(pServiceHandle);
if (h == 0)
return FALSE; // Caller SetLastError()
*phOutHandle = (ce::PSL_HANDLE)h;
DEBUGMSG(ZONE_API,(L"LOC: LocationOpen succeeded. New Location Handle = <0x%08x>\r\n",h));
return TRUE;
}
BOOL LocationCloseIntrnl(
serviceHandle_t *pServiceHandle,
ce::PSL_HANDLE hLocation
)
{
DEBUGMSG(ZONE_API,(L"LOC: LocationClose(0x%08x) called\r\n",hLocation));
DEBUGCHK(g_pLocLock->IsLocked());
return (ERROR_SUCCESS == g_pHandleMgr->FreeLocationHandle((HLOCATION)hLocation));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -