详解MSDN上推荐的分步加载流驱动实现启动提速

 (引用此文需注明来源 http://www.armce.cn WinCE家园)

这个文章讲述的是如何利用BusEnum可以Active自己的特性,把一部分不是启动的时候必须的流驱动延迟到任何时间加载(依然可以用order来控制顺序,只是可以滞后到explorer跑起来后开始)。
原理是这样的,默认的device.exe只加载一个流驱动,它就是busenum.dll,然后其他的流驱动是靠busenum.dll去遍历和Active(加载)的。因为busenum.dll也是流驱动接口的,所以它自己也可以被自己Active,上文就是利用了这个特点,对busenum.dl做了一个微妙的改动,实现了我们可以对流驱动的分批加载,让最关键的dll在出现桌面前加载,其他的都滞后,让用户可以在较短时间见到桌面。
下面来解析实现的具体原理:
默认的,你的注册表肯定有下面的项目:
[HKEY_LOCAL_MACHINE\Drivers]
    "RootKey"="Drivers\\BuiltIn"
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn]
    "Dll"="BusEnum.dll"
    "BusName"="BuiltIn"
    "Flags"=dword:8
    "BusIoctl"=dword:2a0048
    "InterfaceType"=dword:0
    "IClass"=multi_sz:"{B3CC6EBA-5507-4196-8E41-2BF42E4A47C9}=%b","{6F40791D-300E-44E4-BC38-E0E63CA8375C}=%b"
设备管理器Device.exe在初始化的时候会去读上面的rootkey,然后自己加载rootkey指向的那个驱动,这里就是[HKEY_LOCAL_MACHINE\Drivers\BuiltIn],所以在这里busenum.dll就跑起来了。详细的代码自己可以去private下面check,懒的可以看我借用的一篇文章 http://www.armce.cn/bbs/thread-35-1-1.html ,它分析了device.exe的初始化过程,最下一行很有意思。
接下来busenum.dll会开始遍历它键值下面的流驱动并一一加载。比如:
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\SDMEMORY]
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\NAND]
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\PowerButton]
所以类似的,如果你把BusEnum.dll放到[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\hStartEvent]下面并且把她Active起来,它就会去加载所有[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\hStartEvent\*****]键值下的流驱动

 

分时加载已经分组的流驱动

这来讲如何加载两个BusEnum.dll的问题,和如何从时间上把他们分开。
刚才有讲,BusEnum.dll(后启动的)自己是可以被当做普通的流驱动被BusEnum.dll(先启动的,device加载)加载的,比如下面的键值。
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\AsyncBus]
  "Dll"="BusEnum.dll"
  "BusName"="AsyncBus"
  "Order"=dword:10;
  "Flags"=dword:0  
    "BusIoctl"=dword:2a0048
    "InterfaceType"=dword:0
    "IClass"=multi_sz:"{B3CC6EBA-5507-4196-8E41-2BF42E4A47C9}=%b","{6F40791D-300E-44E4-BC38-E0E63CA8375C}=%b"
因为处于BuiltIn下面,所以肯定会被轮询到被加载。但是就简单这么写还不行,虽然它可以实现加载[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\AsyncBus\****]的所有流驱动,但是时间上面它无法控制,它会立刻开始加载操作,无法实现我们从时间上的分批次加载驱动的目的,所以一楼的文章就介绍了一种方法,在上面的键值里面加一个flag,如下:
  "Flags"=dword:408  ; 0x400+0x8 (0x400 is the asyncbus flag)
通过修改busenum.dll的源码,让这个flag会在第二个busenum.dll被加载的时候被第一个busenum读到,我们的例子里面加入的0x400就是代码里面宏定义DEVFLAGS_LOAD_ASYNC的值,第一个busenum就可以判断这个标志不立刻走正常的遍历和加载它,延迟第二个busenum的启动。
下面是一段修改devbus.cpp的一个sample,不去ActivateDeviceEx,而是去调用线程等待启动信号。
if(GetLoadFlag() & DEVFLAGS_LOAD_ASYNC)
{
        HANDLE hAsyncLoadThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) AsyncLoadThread, this, 0, NULL);      
}
else
{
m_hDevice = ActivateDeviceEx(m_lpTemplateRegPath, m_dwInitRegArray,  (m_dwInitRegArray!=NULL?m_dwInitRegCount:0) , NULL);
}
在AsyncLoadThread的线程里面去做类似下面的事情,等待一个hStartEvent事件,以便开始加载第二个busenum.dll. hStartEvent事件要你自己手动去发,比如你可以在explorer.exe起来之后调用一个AP去发这个自定义事件。
WaitForSingleObject(hStartEvent, INFINITE);
NKDbgPrintfW(L"[busenum]Start load %s\r\n",m_lpTemplateRegPath);
   m_hDevice = ActivateDeviceEx(m_lpTemplateRegPath, m_dwInitRegArray,  (m_dwInitRegArray!=NULL?m_dwInitRegCount:0) , NULL);
         m_fDriverLoaded = (m_hDevice!=NULL);
当你的AP调用SetEvent(hStartEvent)后,第二个busenum.dll就开始加载路径位于[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\AsyncBus\****]下的所有驱动,order依然有效。

 

打印消息:
DeviceFolder:oadDevice(Drivers\BuiltIn\SDHC_ZYLONITE2) last 163 Ticks
... ...
ActivateDeviceEx busenum.dll successful.m_lpTemplateRegPath=Drivers\BuiltIn\AsyncBus.
DeviceFolder:oadDevice(Drivers\BuiltIn\PCC_ZYLONITE0) last 1 Ticks
DeviceFolder:oadDevice(Drivers\BuiltIn\PCI) last 0 Ticks
... ...

下面是我的一些代码:

注册表里:
  [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\AsyncBus]
        "Dll"="BusEnum.dll"
        "Order"=dword:10
        "Flags"=dword:1000008
        "BusName"="AsyncBus"
        "LoadAsyncEvent"="Start"            ;wait for the event to load the childkey of AsyncBus
        "LoadAsyncDelay"=dword:2710    ;setup the timeout is 10s

    [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\AsyncBus\SWC]
        "refix"="SWC"
        "Dll"="$(_TGTPLAT_PFX)_SWC.dll"
        "Order"=dword:1  ; Must loading after MFP driver loading   
        "Flags"=dword:0

    [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\AsyncBus\RTC]
        "refix"="RTC"
        "Dll"="$(_TGTPLAT_PFX)_RTC.dll"
        "Order"=dword:2
        "Flags"=dword:0

BOOL DeviceFolder:oadDeviceAsync()
{
    WCHAR  szEventName[MAX_PATH] = {};
    DWORD  dwEventTimeout = 0;

        BOOL aa = GetRegValue(DEVLOAD_LOAD_ASYNC_EVENT_TIMEOUT_VALNAME,(LPBYTE)&dwEventTimeout,sizeof(dwEventTimeout));
               
    if (!aa)
    {
        // no timeout/delay option set.
        dwEventTimeout = INFINITE;
               
    }

        BOOL bb = GetRegValue(DEVLOAD_LOAD_ASYNC_EVENT_VALNAME,(PUCHAR)szEventName,sizeof(szEventName));
        
    if (bb)
    {
        m_hAsyncLoadStartEvent = CreateEvent(NULL, TRUE, FALSE, szEventName);

        if(m_hAsyncLoadStartEvent && dwEventTimeout)
        {
            // Wait for event or timeout
            if(WAIT_FAILED == WaitForSingleObject(m_hAsyncLoadStartEvent, dwEventTimeout))//等待加载信号或超时
            {
                return FALSE;
            }
        }
    }
    else
    {
        // No event option set. Will start loading after delay
        if(dwEventTimeout && (dwEventTimeout != INFINITE))
        {
            Sleep(dwEventTimeout);
        }
    }

    // Time to load the driver.
    m_hDevice = ActivateDeviceEx(m_lpTemplateRegPath, m_dwInitRegArray,  (m_dwInitRegArray!=NULL?m_dwInitRegCount:0) , NULL);

        if (m_hDevice)
        {        //正确加载了第2个BusEnum.dll
        RETAILMSG(1,(TEXT("ActivateDeviceEx busenum.dll successful.m_lpTemplateRegPath=%s.\r\n"), m_lpTemplateRegPath));
        }
        else
        {
                RETAILMSG(1,(TEXT("ActivateDeviceEx faild.\r\n")));
        }
        
    Lock();
    m_PendingLoadAsync = FALSE;
    m_fDriverLoaded = (m_hDevice!=NULL);
    Unlock();

    return m_fDriverLoaded;
}
#endif



BOOL DeviceFolder:oadDevice()
{
    ... ...
                m_hAsyncLoadThread = CreateThread(NULL, 0,
                                     (LPTHREAD_START_ROUTINE) AsyncLoadThread, this, CREATE_SUSPENDED, NULL);

                if(m_hAsyncLoadThread)
                {
                RETAILMSG(1,(TEXT("m_hAsyncLoadThread succeed.\r\n")));
                    Lock();
                    m_PendingLoadAsync = TRUE;
                    Unlock();

                    ResumeThread(m_hAsyncLoadThread);

                    return TRUE;
                }
                // Failed creating the async loading thread for this driver.
                return FALSE;
             }
           m_hDevice = ActivateDeviceEx(m_lpTemplateRegPath, m_dwInitRegArray,  (m_dwInitRegArray!=NULL?m_dwInitRegCount:0) , NULL);
             m_fDriverLoaded = (m_hDevice!=NULL);

         //加载任何BuiltIn下的驱动都会打印
          RETAILMSG(1,(TEXT("DeviceFolder:oadDevice(%s) last %d Ticks\r\n"),m_lpTemplateRegPath,GetTickCount()-dwStartTicks));
... ...
}

你可能感兴趣的:(详解MSDN上推荐的分步加载流驱动实现启动提速)