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: