Services

1 概述

1服務程序遵循Service Control Manager(SCM)的接口規則。 啟動方式由3種:1 系統啟動時自動啟動;2 通過服務控制面板;3 通過使用服務函數。2服務可以在沒有用戶登錄到系統的情況下運行。

2 驅動服務驅動服務遵循設備驅動協議,它與服務程序類似,但是不與SCM交互。

3 The SCM processes service control notifications in a serial fashion

4 The default security descriptor allows the LocalSystem account, and members of the Administrators and Power Users groups to stop and start services.

 

2 服務在Win7中的新特性

1 可以注冊一個服務,在一個特定事件發生時啟動或者停止服務。

更新的函數

ChangeServiceConfig

Changes the configuration parameters of a service. This function supports managed service accounts and virtual accounts. For more information, see Service Accounts Step-by-Step Guide.

ChangeServiceConfig2

Changes the optional configuration parameters of a service. This function supports new configuration information levels for processor groups and service trigger events.

CreateService

Creates a service object and adds it to the specified service control manager database. This function supports managed service accounts and virtual accounts. For more information, see Service Accounts Step-by-Step Guide.

HandlerEx

An application-defined callback function used with the RegisterServiceCtrlHandlerEx function. This callback function supports new extended control codes for system time changes and service trigger events.

QueryServiceConfig2

Retrieves the optional configuration parameters of a service. This function supports new configuration information levels for processor groups and service trigger events.

SetServiceStatus

Updates the service control manager's status information for the calling service. This function supports new extended control codes for system time changes and service trigger events.

 

新的結構

SERVICE_TIMECHANGE_INFO

Contains system time change settings.

SERVICE_TRIGGER

Represents a service trigger event.

SERVICE_TRIGGER_INFO

Contains trigger event information for a service.

SERVICE_TRIGGER_SPECIFIC_DATA_ITEM

Contains trigger-specific data for a service trigger event.

Service Changes for Windows Vista

 

為了提高性能、可靠性、安全性、可管理性等,在Vista之后,服務提供了很多增強的特性。

 

Session 0 Isolation

服務總是運行在Session 0,在Vista之前,第一個用戶也是運行在Session0,在Vista之后,第一個用戶運行在Session1,第二個用戶運行在Session2 等等,這樣用戶程序和服務就始終運行在不同的Session上。Session 0 不支持與用戶交互的進程。這就意味著Service不能向應用程序發送消息,應用程序也不能像Service發送消息。除此之外,Service還不能顯示GUI,如對話框,但是Service可以使用WTSSendMessage 函數在另一個Session中顯示對話框。

Delayed AutoStart 在系統啟動的一小段時間(shortly after)內啟動服務。

Failure Detection and Recovery:如果服務失敗,SCM可以執行失敗action,如重啟服務。

Preshutdown Notifications:是服務有足夠的時間來優雅的關閉。

Restricted Network Acess

Running with Least Privilage

 

關于服務

SCM維護者已安裝的服務和驅動服務的數據庫,并且提供了統一的安全的控制它們的方法。數據庫信息包括每個服務如何被啟動。

下面類型的程序使用SCM提供的函數:

服務程序(Service Program):一個為一個或者多個服務提供可執行代碼的程序。服務程序使用連接到SCM的函數以及發送狀態信息給SCM的函數。

服務配置程序(Service configuration program):一個查詢和修改服務數據庫的程序。服務配置程序使用打開數據庫的函數,在數據庫中安裝和刪除服務,對安裝的服務查詢和修改配置參數,安全參數。服務配置程序管理服務以及驅動服務。

服務控制程序(Service Control Program):一個啟動并控制服務以及驅動服務的程序。服務控制程序使用發送請求到SCM的函數。

Service Control Manager(服務控制管理器)

1 系統啟動時啟動;它是一個RPC (Remote procedure call) 服務器。所以服務配置和服務控制程序可以在遠程機器上管理服務。

提供接口功能:

管理安裝服務的數據庫;

啟動服務(系統啟動時,或者需要時)

枚舉安裝的服務

為運行的服務維護狀態信息

傳輸控制請求(control request)給正在運行的服務

鎖定和解鎖服務數據庫。

Database of installed service

在注冊表中維護著已安裝的服務列表。注冊表如下

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services.

這個鍵值為每一個安裝的服務包含一個子鍵,子鍵的名字就是服務名。

Database又叫作ServiceActive databse或者SCM database。你必須使用SCM提供的函數,而不能直接修改databse,即不能直接修改注冊表。

自動啟動服務

在系統啟動的時候,SCM將啟動所有自啟動的服務以及它們依賴的服務。

啟動順序:

1 按加載啟動組列表中的順序;這個信息保存在ServiceGroupOrder值中,

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control

2 GroupOrderList

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control

3 每個服務的依賴列表

當啟動完成后,系統執行啟動認證程序(boot verification program)根據BootVerificationProgram

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control.

默認情況下,這個值是沒有設置的。你可以提供程序來檢測系統,調用NotifyBootConfigStatus通知SCM,報告boot 狀態。

在成功重啟后,系統會將組冊表復制一份到下面目錄下last-known-good (LKG) configuration

HKEY_LOCAL_MACHINE\SYSTEM\ControlSetXXX\Services

按需啟動服務

當服務啟動之后,SCM執行下列步驟:

獲取存儲在數據庫中的帳戶信息

登錄到服務帳戶

加載用戶配置

在暫停狀態下創建服務

給進程分配一個Logontoken

允許進程執行

Service Record List

由于每個服務實體是從注冊表數據庫中讀取的,因此SCM為每個服務創建了一個Service Record

一個Service Record包括:

服務名

啟動類型

服務狀態(SERVICE_STATUS結構)

指向依賴服務列表的指針

服務在安裝的時候用戶名和密碼是指定好的。SCM在注冊表中存放用戶名,在Local Security AuthorityLSA)中存放密碼。

SCM保存兩份用戶密碼。一個當前密碼和一個備份密碼。在服務第一次安裝的時候使用當前密碼,備份密碼是未初始化的。當用當前密碼運行服務成功后,才會將當前密碼寫入到備份密碼。SCM在收到服務狀態通知后更新服務狀態。

驅動服務的狀態是通過查詢IO系統獲得的,而不是通過狀態通知,這點是與Service不同的。

SCM Handles

SCM支持句柄(Handle)來訪問下面的對象。

已安裝的服務的數據庫:用SCManager object來表示

服務:由一個安裝的服務代表服務對象。

數據庫鎖

Service Programs服務程序

Main函數:

調用StartServiceCtrlDispatcher函數連接到SCM并啟動control dispatcher線程。Control dispatcher線程循環loop,等待在dispatch table中指定的服務的請求。

例子:

void __cdecl _tmain(int argc, TCHAR *argv[])

{

    // If command-line parameter is "install", install the service.

    // Otherwise, the service is probably being started by the SCM.

 

    if( lstrcmpi( argv[1], TEXT("install")) == 0 )

    {

        SvcInstall();

        return;

    }

 

    // TO_DO: Add any additional services for the process to this table.

    SERVICE_TABLE_ENTRY DispatchTable[] =

    {

        { SVCNAME, (LPSERVICE_MAIN_FUNCTION) SvcMain },

        { NULL, NULL }

    };

 

    // This call returns when the service has stopped.

    // The process should simply terminate when the call returns.

 

    if (!StartServiceCtrlDispatcher( DispatchTable ))

    {

        SvcReportEvent(TEXT("StartServiceCtrlDispatcher"));

    }

}

ServiceMain函數:

首先調用RegisterServiceCtrlHandler函數來注冊SvcCtrHandler函數作為服務的處理函數,然后開始初始化。

VOID WINAPI SvcMain( DWORD dwArgc, LPTSTR *lpszArgv )

{

    // Register the handler function for the service

 

    gSvcStatusHandle = RegisterServiceCtrlHandler(

        SVCNAME,

        SvcCtrlHandler);

 

    if( !gSvcStatusHandle )

    {

        SvcReportEvent(TEXT("RegisterServiceCtrlHandler"));

        return;

    }

 

    // These SERVICE_STATUS members remain as set here

 

    gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;

    gSvcStatus.dwServiceSpecificExitCode = 0;   

 

    // Report initial status to the SCM

 

    ReportSvcStatus( SERVICE_START_PENDING, NO_ERROR, 3000 );

 

    // Perform service-specific initialization and work.

 

    SvcInit( dwArgc, lpszArgv );

}

 

//

// Purpose:

//   The service code

//

// Parameters:

//   dwArgc - Number of arguments in the lpszArgv array

//   lpszArgv - Array of strings. The first string is the name of

//     the service and subsequent strings are passed by the process

//     that called the StartService function to start the service.

//

// Return value:

//   None

//

VOID SvcInit( DWORD dwArgc, LPTSTR *lpszArgv)

{

    // TO_DO: Declare and set any required variables.

    //   Be sure to periodically call ReportSvcStatus() with

    //   SERVICE_START_PENDING. If initialization fails, call

    //   ReportSvcStatus with SERVICE_STOPPED.

 

    // Create an event. The control handler function, SvcCtrlHandler,

    // signals this event when it receives the stop control code.

 

    ghSvcStopEvent = CreateEvent(

                         NULL,    // default security attributes

                         TRUE,    // manual reset event

                         FALSE,   // not signaled

                         NULL);   // no name

 

    if ( ghSvcStopEvent == NULL)

    {

        ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );

        return;

    }

 

    // Report running status when initialization is complete.

 

    ReportSvcStatus( SERVICE_RUNNING, NO_ERROR, 0 );

 

    // TO_DO: Perform work until service stops.

 

    while(1)

    {

        // Check whether to stop the service.

 

        WaitForSingleObject(ghSvcStopEvent, INFINITE);

 

        ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );

        return;

    }

}

 

//

// Purpose:

//   Sets the current service status and reports it to the SCM.

//

// Parameters:

//   dwCurrentState - The current state (see SERVICE_STATUS)

//   dwWin32ExitCode - The system error code

//   dwWaitHint - Estimated time for pending operation,

//     in milliseconds

//

// Return value:

//   None

//

VOID ReportSvcStatus( DWORD dwCurrentState,

                      DWORD dwWin32ExitCode,

                      DWORD dwWaitHint)

{

    static DWORD dwCheckPoint = 1;

 

    // Fill in the SERVICE_STATUS structure.

 

    gSvcStatus.dwCurrentState = dwCurrentState;

    gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;

    gSvcStatus.dwWaitHint = dwWaitHint;

 

    if (dwCurrentState == SERVICE_START_PENDING)

        gSvcStatus.dwControlsAccepted = 0;

    else gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;

 

    if ( (dwCurrentState == SERVICE_RUNNING) ||

           (dwCurrentState == SERVICE_STOPPED) )

        gSvcStatus.dwCheckPoint = 0;

    else gSvcStatus.dwCheckPoint = dwCheckPoint++;

 

    // Report the status of the service to the SCM.

    SetServiceStatus( gSvcStatusHandle, &gSvcStatus );

}

 

Control Handler函數:

該函數是由dispatcher thread調用的,它處理在OpCode參數中傳進來的控制碼,然后調用ReportSvcStatus函數來更新服務狀態。當Handler收到控制碼時,只有當收到的控制碼引起服務狀態變化時才報告服務狀態。

VOID WINAPI SvcCtrlHandler( DWORD dwCtrl )

{

   // Handle the requested control code.

 

   switch(dwCtrl)

  

      case SERVICE_CONTROL_STOP:

         ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);

 

         // Signal the service to stop.

 

         SetEvent(ghSvcStopEvent);

         ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);

        

         return;

 

      case SERVICE_CONTROL_INTERROGATE:

         break;

 

      default:

         break;

   }

  

}

Service Configuration Program Tasks服務配置程序的任務

安裝服務

刪除服務

改變服務配置

查詢服務配置

Service Control Program Tasks服務控制程序任務

啟動服務

停止服務

改變一個服務的DACL

 

Service Functions

The following functions are used or implemented by services.

Function

Description

Handler

An application-defined callback function used with the RegisterServiceCtrlHandler function.

HandlerEx

An application-defined callback function used with the RegisterServiceCtrlHandlerEx function.

RegisterServiceCtrlHandler

Registers a function to handle service control requests.

RegisterServiceCtrlHandlerEx

Registers a function to handle extended service control requests.

ServiceMain

An application-defined function that serves as the starting point for a service.

SetServiceBits

Registers a service type with the service control manager and the Server service.

SetServiceStatus

Updates the service control manager's status information for the calling service.

StartServiceCtrlDispatcher

Connects the main thread of a service process to the service control manager.

 

The following functions are used by programs that control or configure services.

Function

Description

ChangeServiceConfig

Changes the configuration parameters of a service.

ChangeServiceConfig2

Changes the optional configuration parameters of a service.

CloseServiceHandle

Closes the specified handle to a service control manager object or a service object.

ControlService

Sends a control code to a service.

ControlServiceEx

Sends a control code to a service.

CreateService

Creates a service object and adds it to the specified service control manager database.

DeleteService

Marks the specified service for deletion from the service control manager database.

EnumDependentServices

Retrieves the name and status of each service that depends on the specified service.

EnumServicesStatusEx

Enumerates services in the specified service control manager database based on the specified information level.

GetServiceDisplayName

Retrieves the display name of the specified service.

GetServiceKeyName

Retrieves the service name of the specified service.

NotifyBootConfigStatus

Reports the boot status to the service control manager.

NotifyServiceStatusChange

Enables an application to receive notification when the specified service is created or deleted or when its status changes.

OpenSCManager

Establishes a connection to the service control manager on the specified computer and opens the specified service control manager database.

OpenService

Opens an existing service.

QueryServiceConfig

Retrieves the configuration parameters of the specified service.

QueryServiceConfig2

Retrieves the optional configuration parameters of the specified service.

QueryServiceObjectSecurity

Retrieves a copy of the security descriptor associated with a service object.

QueryServiceStatusEx

Retrieves the current status of the specified service based on the specified information level.

SetServiceObjectSecurity

Sets the security descriptor of a service object.

StartService

Starts a service.

Service Structures

The following structures are used with services: