// BrokerServices exposes all the broker API. // The basic use is to start the target(s) and wait for them to end. // // This API is intended to be called in the following order // (error checking omitted): // BrokerServices* broker = SandboxFactory::GetBrokerServices(); // broker->Init(); // PROCESS_INFORMATION target; // broker->SpawnTarget(target_exe_path, target_args, &target); // ::ResumeThread(target->hThread); // // -- later you can call: // broker->WaitForAllTargets(option); // // 彻头彻尾的抽象基类,只提供了4个纯虚函数接口 classBrokerServices { public: // Initializes the broker. Must be called before any other on this class. // returns ALL_OK if successful. All other return values imply failure. // If the return is ERROR_GENERIC, you can call ::GetLastError() to get // more information. virtual ResultCode Init()= 0;//chrome经典的Init
// Returns the interface pointer to a new, empty policy object. Use this // interface to specify the sandbox policy for new processes created by // SpawnTarget() // 对生成的target进程所应用的沙盒策略,这是标准的职能分离 // scoped_refptr是个类模板,实现了智能指针机制,指向TargetPolicy对象 // TargetPolicy是个管理target进程Policy的对象,policy相当复杂,暂不关心 virtual scoped_refptr<TargetPolicy> CreatePolicy()= 0;
// Creates a new target (child process) in a suspended state. // Parameters: // exe_path: This is the full path to the target binary. This parameter // can be null and in this case the exe path must be the first argument // of the command_line. // command_line: The arguments to be passed as command line to the new // process. This can be null if the exe_path parameter is not null. // policy: This is the pointer to the policy object for the sandbox to // be created. // last_warning: The argument will contain an indication on whether // the process security was initialized completely, Only set if the // process can be used without a serious compromise in security. // last_error: If an error or warning is returned from this method this // parameter will hold the last Win32 error value. // target: returns the resulting target process information such as process // handle and PID just as if CreateProcess() had been called. The caller is // responsible for closing the handles returned in this structure. // Returns: // ALL_OK if successful. All other return values imply failure. // 实际上就是CreateProcess的封装了 virtual ResultCode SpawnTarget(constwchar_t* exe_path, constwchar_t* command_line, scoped_refptr<TargetPolicy> policy, ResultCode* last_warning, DWORD* last_error, PROCESS_INFORMATION* target)= 0;
// This call blocks (waits) for all the targets to terminate. // Returns: // ALL_OK if successful. All other return values imply failure. // If the return is ERROR_GENERIC, you can call ::GetLastError() to get // more information. // 实际上就是WaitForSingleObject的封装 virtual ResultCode WaitForAllTargets()= 0;
// sandbox的工厂类 classSandboxFactory { public: // Returns the Broker API interface, returns nullptr if this process is the // target. static BrokerServices* GetBrokerServices();//生产broker
// Returns the Target API interface, returns nullptr if this process is the // broker. static TargetServices* GetTargetServices();//生产target
// GetBrokerServices: the current implementation relies on a shared section // that is created by the broker and opened by the target. BrokerServices* SandboxFactory::GetBrokerServices(){ // Can't be the broker if the shared section is open. // 看起来这个HANDLE有效时,其调用进程不是broker,而是target // 根据g_shared_section的注释来看,它作为target/broker间IPC和policy交互的共享内存的句柄,所以我猜测它的初始化应该在broker进程调用该函数之后。 if (g_shared_section) returnnullptr; // If the shared section does not exist we are the broker, then create // the broker object. // s_is_broker是个static全局量,看起来也只在两个工厂方法里用到,分别表示是否是broker进程,但因为是个static的全局变量,该文件的其他位置也没有用到这货,可能是个reserved备胎吧。 s_is_broker = true; //这里就是关键的对象生成了,BrokerServices是抽象基类显然不干实业,BrokerServices的派生类是BrokerServicesBase,负责干活。 return BrokerServicesBase::GetInstance(); }
// BrokerServicesBase --------------------------------------------------------- // Broker implementation version 0 // // This is an implementation of the interface BrokerServices and // of the associated TargetProcess interface. In this implementation // TargetProcess is a friend of BrokerServices where the later manages a // collection of the former. // 公有多继承BrokerServices和SingletonBase<BrokerServicesBase>类 // SingletonBase是个类模板,这里是对BrokerServicesBase应用了单例模式 // final表示不可被派生,也就表示这是最终实现体。 classBrokerServicesBasefinal : public BrokerServices, public SingletonBase<BrokerServicesBase> { public: BrokerServicesBase();
// Checks if the supplied process ID matches one of the broker's active // target processes // Returns: // true if there is an active target process for this ID, otherwise false. // 检查指定进程ID是否在broker的活跃目标进程集中 boolIsActiveTarget(DWORD process_id);
private: // The routine that the worker thread executes. It is in charge of // notifications and cleanup-related tasks. // 工作线程routine,负责通知和清理相关的任务。 // 应该是有谁用该static函数作为一个独立运行的线程,但既然是private,就应该源于内部 static DWORD WINAPI TargetEventsThread(PVOID param);
// The completion port used by the job objects to communicate events to // the worker thread. // base::win::ScopedHandle是对Windows句柄HANDLE的一个封装,暂不理 base::win::ScopedHandle job_port_; //Job对象用此I/O完成端口与工作线程进行事件通信
// Handle to a manual-reset event that is signaled when the total target // process count reaches zero. base::win::ScopedHandle no_targets_; //这是个手动重置event,当全部target进程计数降到0时,signaled置信
// Handle to the worker thread that reacts to job notifications. base::win::ScopedHandle job_thread_; //响应job通知的工作线程句柄
// Lock used to protect the list of targets from being modified by 2 // threads at the same time. CRITICAL_SECTION lock_; //锁,防止target链同时被两个线程修改
// Provides a pool of threads that are used to wait on the IPC calls. std::unique_ptr<ThreadProvider> thread_pool_; //线程池,用于等待IPC调用
// List of the trackers for closing and cleanup purposes. std::list<std::unique_ptr<JobTracker>> tracker_list_; //关闭和清理的tracker list
// Provides a fast lookup to identify sandboxed processes that belong to a // job. Consult |jobless_process_handles_| for handles of processes without // jobs. std::set<DWORD> child_process_ids_;//属于job对象的沙盒进程id集,可用于快速检索
// The destructor should only be called when the Broker process is terminating. // Since BrokerServicesBase is a singleton, this is called from the CRT // termination handlers, if this code lives on a DLL it is called during // DLL_PROCESS_DETACH in other words, holding the loader lock, so we cannot // wait for threads here. BrokerServicesBase::~BrokerServicesBase() { // If there is no port Init() was never called successfully. if (!job_port_.IsValid()) return;
// Closing the port causes, that no more Job notifications are delivered to // the worker thread and also causes the thread to exit. This is what we // want to do since we are going to close all outstanding Jobs and notifying // the policy objects ourselves. // 关闭I/O完成端口,Job通知不再转给工作线程,工作线程也会退出 ::PostQueuedCompletionStatus(job_port_.Get(), 0, THREAD_CTRL_QUIT, nullptr);
// The broker uses a dedicated worker thread that services the job completion // port to perform policy notifications and associated cleanup tasks. ResultCode BrokerServicesBase::Init(){ if (job_port_.IsValid() || thread_pool_) //防止二次Init return SBOX_ERROR_UNEXPECTED_CALL;
//初始化用户态临界区锁 ::InitializeCriticalSection(&lock_);
//创建IO完成端口,job_port是个封装的windows HANDLE类,Set方法关联 job_port_.Set(::CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 0)); if (!job_port_.IsValid()) return SBOX_ERROR_GENERIC;
// SpawnTarget does all the interesting sandbox setup and creates the target // process inside the sandbox. // 负责沙盒的安装、target进程的创建,是个相当复杂的函数 ResultCode BrokerServicesBase::SpawnTarget(constwchar_t* exe_path, constwchar_t* command_line, scoped_refptr<TargetPolicy> policy, ResultCode* last_warning, DWORD* last_error, PROCESS_INFORMATION* target_info){ //target process二进制全路径,这里不能为NULL //实际上这里的实现体和虚基类的说法不太一致,虚基类的纯虚接口允许exe_path为NULL,但此时command_line的第一元必须为exe_path if (!exe_path) return SBOX_ERROR_BAD_PARAMS;
//应用于target进程的policy也不能为空,必须要提前通过CreatePolicy创建好,传入参数在该函数内关联,暂且先不管CreatePolicy做了什么。 if (!policy) return SBOX_ERROR_BAD_PARAMS;
// Even though the resources touched by SpawnTarget can be accessed in // multiple threads, the method itself cannot be called from more than // 1 thread. This is to protect the global variables used while setting up // the child process. // 这里的static局部变量以及锁是对线程重入做的限制,尽管SpawnTarget中资源可以被多个线程访问,但该方法本身一次只能有1个线程调用 static DWORD thread_id = ::GetCurrentThreadId(); // 到这里如果两次id不一致,说明是A->B->A,B改变了A设置的static thread_id // 这个时候A就应该终止,由B继续进行 DCHECK(thread_id == ::GetCurrentThreadId()); *last_warning = SBOX_ALL_OK;
// This downcast is safe as long as we control CreatePolicy() // policy尽管是 scoped_refptr<TargetPolicy>对象,但实际上CreatePolicy()时父类引用调用的是子类PolicyBase对象成员函数,标准的多态 // 之所以做了向下转型,是因为虚基类TargetPolicy并没有定义要如何实现安全策略,使用了token、job等策略的PolicyBase只是一种实现体罢了。这就是OO的魅力,扩展性极强。 // 当然,向下转型的使用前提是,必须已知父类引用指向的是某个具体的派生类,且只能是该派生类。 scoped_refptr<PolicyBase> policy_base(static_cast<PolicyBase*>(policy.get()));
// Construct the tokens and the job object that we are going to associate // with the soon to be created target process. // 构造三个信令token以及job对象,与即将创建的target进程相关联 base::win::ScopedHandle initial_token; base::win::ScopedHandle lockdown_token; base::win::ScopedHandle lowbox_token; ResultCode result = SBOX_ALL_OK;
// 可以看到三个信令token的部署是policy_base执行的,token是policy的三大核心之一(另外两个是job和alternative desktop) // 至于token是如何部署的,这个疑问留到解剖TargetPolicy时再探索 result = policy_base->MakeTokens(&initial_token, &lockdown_token, &lowbox_token); if (SBOX_ALL_OK != result) return result; // lowbox_token必须要Win8以上才可用 // 我觉着把这个逻辑放在MakeTokens后面挺奇怪的 if (lowbox_token.IsValid() && base::win::GetVersion() < base::win::VERSION_WIN8) { // We don't allow lowbox_token below Windows 8. return SBOX_ERROR_BAD_PARAMS; }
// policy的三大核心之job部署,依然是依赖policy_base base::win::ScopedHandle job; result = policy_base->MakeJobObject(&job); if (SBOX_ALL_OK != result) return result;
// StartupInformation是windows的STARTUPINFOEX的封装 // spawn进程的时候会用到,这个结构理应耳熟能详 // Initialize the startup information from the policy. base::win::StartupInformation startup_info; // The liftime of |mitigations|, |inherit_handle_list| and // |child_process_creation| have to be at least as long as // |startup_info| because |UpdateProcThreadAttribute| requires that // its |lpValue| parameter persist until |DeleteProcThreadAttributeList| is // called; StartupInformation's destructor makes such a call. DWORD64 mitigations[2]; std::vector<HANDLE> inherited_handle_list; DWORD child_process_creation = PROCESS_CREATION_CHILD_PROCESS_RESTRICTED;
if (stdout_handle != INVALID_HANDLE_VALUE) inherited_handle_list.push_back(stdout_handle);
// Handles in the list must be unique. if (stderr_handle != stdout_handle && stderr_handle != INVALID_HANDLE_VALUE) inherited_handle_list.push_back(stderr_handle);
//标准输出,标准错误和policy的所有共享句柄全部放入inherited_handle_list for (HANDLE handle : policy_handle_list) inherited_handle_list.push_back(handle);
if (inherited_handle_list.size()) ++attribute_count;
//AppContainer可以在Win8以上使用 scoped_refptr<AppContainerProfileBase> profile = policy_base->GetAppContainerProfileBase(); if (profile) { if (base::win::GetVersion() < base::win::VERSION_WIN8) return SBOX_ERROR_BAD_PARAMS; ++attribute_count; if (profile->GetEnableLowPrivilegeAppContainer()) { // LPAC first supported in RS1. // Win10_RS1以上可以应用LPAC if (base::win::GetVersion() < base::win::VERSION_WIN10_RS1) return SBOX_ERROR_BAD_PARAMS; ++attribute_count;// LPAC与AC各算一次计数 } }
//初始化startup_info的线程属性列表,attribute_count记录了属性的个数 if (!startup_info.InitializeProcThreadAttributeList(attribute_count)) return SBOX_ERROR_PROC_THREAD_ATTRIBUTES;
//UpdateProcThreadAttribute用以更新线程属性PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY if (mitigations[0] || mitigations[1]) { if (!startup_info.UpdateProcThreadAttribute( PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &mitigations[0], mitigations_size)) { return SBOX_ERROR_PROC_THREAD_ATTRIBUTES; } }
//如果有子进程不允许创建的限制,那么还要更新PROC_THREAD_ATTRIBUTE_CHILD_PROCESS_POLICY这一属性 if (restrict_child_process_creation) { if (!startup_info.UpdateProcThreadAttribute( PROC_THREAD_ATTRIBUTE_CHILD_PROCESS_POLICY, &child_process_creation, sizeof(child_process_creation))) { return SBOX_ERROR_PROC_THREAD_ATTRIBUTES; } }
//更新PROC_THREAD_ATTRIBUTE_HANDLE_LIST属性 if (inherited_handle_list.size()) { if (!startup_info.UpdateProcThreadAttribute( PROC_THREAD_ATTRIBUTE_HANDLE_LIST, &inherited_handle_list[0], sizeof(HANDLE) * inherited_handle_list.size())) { return SBOX_ERROR_PROC_THREAD_ATTRIBUTES; } startup_info.startup_info()->dwFlags |= STARTF_USESTDHANDLES; startup_info.startup_info()->hStdInput = INVALID_HANDLE_VALUE; // policy的标准输出和错误句柄为新进程使用,同时也在可继承句柄列表中 startup_info.startup_info()->hStdOutput = stdout_handle; startup_info.startup_info()->hStdError = stderr_handle; // Allowing inheritance of handles is only secure now that we // have limited which handles will be inherited. inherit_handles = true;//仅在控制了哪些句柄可以被继承的情况下,允许继承句柄才是安全的 }
// Declared here to ensure they stay in scope until after process creation. std::unique_ptr<SecurityCapabilities> security_capabilities; DWORD all_applications_package_policy = PROCESS_CREATION_ALL_APPLICATION_PACKAGES_OPT_OUT;
//如果应用了AppContainer,还要更新PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES // SecurityCapabilities对象源于profile,AC相关的部分我还没有看,暂时不清楚技术内幕 if (profile) { security_capabilities = profile->GetSecurityCapabilities(); if (!startup_info.UpdateProcThreadAttribute( PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES, security_capabilities.get(), sizeof(SECURITY_CAPABILITIES))) { return SBOX_ERROR_PROC_THREAD_ATTRIBUTES; } //如果应用了LPAC,还要更新PROC_THREAD_ATTRIBUTE_ALL_APPLICATION_PACKAGES_POLICY if (profile->GetEnableLowPrivilegeAppContainer()) { if (!startup_info.UpdateProcThreadAttribute( PROC_THREAD_ATTRIBUTE_ALL_APPLICATION_PACKAGES_POLICY, &all_applications_package_policy, sizeof(all_applications_package_policy))) { return SBOX_ERROR_PROC_THREAD_ATTRIBUTES; } } }
// Construct the thread pool here in case it is expensive. // The thread pool is shared by all the targets // 首次创建target时,初始化线程池 // Win2kThreadPool是Win2k线程池API的实现 // 这里使用的是个std::unique_ptr,防止其他指针指向该对象 if (!thread_pool_) thread_pool_ = std::make_unique<Win2kThreadPool>();
// Create the TargetProcess object and spawn the target suspended. Note that // Brokerservices does not own the target object. It is owned by the Policy. // 创建TargetProcess对象,生成挂起的target进程。 // target不属于BrokerServices,它实际上属于Policy。 // base::win::ScopedProcessInformation是对PROCESS_INFORMATION的封装 base::win::ScopedProcessInformation process_info; // 创建TargetProcess对象 // 传递各种policy相关资源,注意如果没有用AppContainer就使用Sid机制 TargetProcess* target = newTargetProcess( std::move(initial_token), std::move(lockdown_token), job.Get(), thread_pool_.get(), profile ? profile->GetImpersonationCapabilities() : std::vector<Sid>());
if (result != SBOX_ALL_OK) { SpawnCleanup(target); return result; }
// lowbox_token是win8以上独有的,单独处理,TargetProcess特意给了个接口 if (lowbox_token.IsValid()) { *last_warning = target->AssignLowBoxToken(lowbox_token); // If this fails we continue, but report the error as a warning. // This is due to certain configurations causing the setting of the // token to fail post creation, and we'd rather continue if possible. // lowbox_token的失败是可以接受的,仅仅记录错误继续前行 if (*last_warning != SBOX_ALL_OK) *last_error = ::GetLastError(); }
// Now the policy is the owner of the target. // policy正式接管target result = policy_base->AddTarget(target);
// We are going to keep a pointer to the policy because we'll call it when // the job object generates notifications using the completion port. // policy和target关联起来了,但broker生成的policy目前却没法找到 // broker通过tracker_list_成员维护tracker,而tracker维护job和policy // 注意局部变量对象job通过std::move转移了owner // 通过JobTracker将job通知与job和policy对象联系起来 if (job.IsValid()) { std::unique_ptr<JobTracker> tracker = std::make_unique<JobTracker>(std::move(job), policy_base);
// There is no obvious recovery after failure here. Previous version with // SpawnCleanup() caused deletion of TargetProcess twice. crbug.com/480639 // 将IO完成端口句柄job_port_与job对象相关联 // tracker指针做key,IO完成端口句柄做value CHECK(AssociateCompletionPort(tracker->job.Get(), job_port_.Get(), tracker.get()));
// Save the tracker because in cleanup we might need to force closing // the Jobs. // tracker是unique_ptr,所以不能直接复制,需要std::move右值引用来转换owner为tracker_list_成员 tracker_list_.push_back(std::move(tracker)); // 维护target进程的id child_process_ids_.insert(process_info.process_id()); } else { // Leak policy_base. This needs to outlive the child process, but there's // nothing that tracks that lifetime properly if there's no job object. // TODO(wfh): Find a way to make this have the correct lifetime. policy_base->AddRef();
// We have to signal the event once here because the completion port will // never get a message that this target is being terminated thus we should // not block WaitForAllTargets until we have at least one target with job. // 大概的意思就是,这个target没有job对象,所以终止时也没办法通知IO完成端口 // 这就可能导致在当前没有任何一个其他拥有job对象的target时,一旦调用WaitForAllTargets // 就会因为收不到该进程终止的消息而永久阻塞,所以这里在没有其他拥有job对象的target进程存在的情况下启动这样一个进程时 // 就手工置信no_targets_信号量,防止WaitForAllTargets的阻塞 // 但这也意味着这种游离于IO完成端口管理之外的target,lifetime不受控制 // 我暂时也不清楚什么样的target会落入到这里 if (child_process_ids_.empty()) ::SetEvent(no_targets_.Get()); }
scoped_refptr<TargetPolicy> BrokerServicesBase::CreatePolicy(){ // If you change the type of the object being created here you must also // change the downcast to it in SpawnTarget(). // 父类指针引用子类对象,标准的多态 scoped_refptr<TargetPolicy> policy(new PolicyBase); // PolicyBase starts with refcount 1. policy->Release(); return policy; }
// The worker thread stays in a loop waiting for asynchronous notifications // from the job objects. Right now we only care about knowing when the last // process on a job terminates, but in general this is the place to tell // the policy about events. // 循环等待各个target的job对象的异步通知 // 当前仅关心最后一个进程何时退出,实际上它可以用来通知policy event的发生 // (这是因为绑定IO完成端口与job对象时,tracker指针做了key,而tracker维护了job和policy) DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param){ if (!param) return1;
// IO完成端口获取事件 if (!::GetQueuedCompletionStatus(port, &events, &key, &ovl, INFINITE)) { // this call fails if the port has been closed before we have a // chance to service the last packet which is 'exit' anyway so // this is not an error. return1; }
// 具体key代表什么现在不得而知,得拆解IO完成端口的信源才行 if (key > THREAD_CTRL_LAST) { // The notification comes from a job object. There are nine notifications // that jobs can send and some of them depend on the job attributes set. // 看起来key大于THREAD_CTRL_LAST时表示通知是从job对象发过来的,一共有9种通知 // 原来这个key就是JobTracker指针,在前面SpawnTarget中创建JobTracker时,曾用此作为JOBOBJECT_ASSOCIATE_COMPLETION_PORT的第一元素,port作为第二元素 // 而JobTracker本身是job和policy的关联 JobTracker* tracker = reinterpret_cast<JobTracker*>(key);
// events指定哪种通知 switch (events) { case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO: { // The job object has signaled that the last process associated // with it has terminated. Assuming there is no way for a process // to appear out of thin air in this job, it safe to assume that // we can tell the policy to destroy the target object, and for // us to release our reference to the policy object. // job对象告知最后一个进程已终止,通过tracker来释放所有相关资源。 tracker->FreeResources(); break; }
case JOB_OBJECT_MSG_NEW_PROCESS: { DWORD handle = static_cast<DWORD>(reinterpret_cast<uintptr_t>(ovl)); { AutoLock lock(&broker->lock_); size_t count = broker->child_process_ids_.count(handle); // Child process created from sandboxed process. // 如果新创建的进程不在broker的child_process_ids中,说明是沙盒中某个target进程创建的子进程,此时要untracked_target_counter递增以维护计数 if (count == 0) untracked_target_counter++; } // 无论是target进程还是某个target创建的子进程,都要递增计数 ++target_counter; // 当从0到1时,no_targets event也需要手工nonsignaled if (1 == target_counter) { ::ResetEvent(no_targets); } break; }
case JOB_OBJECT_MSG_EXIT_PROCESS: case JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS: { size_t erase_result = 0; { AutoLock lock(&broker->lock_); // 删除对应的process id erase_result = broker->child_process_ids_.erase( static_cast<DWORD>(reinterpret_cast<uintptr_t>(ovl))); } if (erase_result != 1U) { // The process was untracked e.g. a child process of the target. // 不在child_process_ids_中,说明是target生成的子进程 --untracked_target_counter; DCHECK(untracked_target_counter >= 0); } --target_counter; // 和楼上相反的操作 if (0 == target_counter) ::SetEvent(no_targets);
DCHECK(target_counter >= 0); break; }
// 这种情况为什么还要递增计数,我不太懂 // 会不会有某种手法一直发这个消息,让int型的untracked_target_counter和target_counter溢出? case JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT: { // A child process attempted and failed to create a child process. // Windows does not reveal the process id. untracked_target_counter++; target_counter++; break; }
// 一旦超过了内存限制,直接终止job case JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT: { bool res = ::TerminateJobObject(tracker->job.Get(), SBOX_FATAL_MEMORY_EXCEEDED); DCHECK(res); break; }
default: { NOTREACHED(); break; } } } elseif (THREAD_CTRL_QUIT == key) { // The broker object is being destroyed so the thread needs to exit. // 如果key是THREAD_CTRL_QUIT,那么broker对象就已经被销毁了,这个线程也就没有存在的必要了。(该线程是static成员,和broker实例的lifetime没关系) return0; } else { // We have not implemented more commands. NOTREACHED(); } }
// Basic implementation of a singleton which calls the destructor // when the exe is shutting down or the DLL is being unloaded. template <typename Derived> classSingletonBase { public: //相当标准的饿汉单例模式实现,SingletonBase没必要产生实例,所以直接将GetInstance作为static public方法公开即可 static Derived* GetInstance(){ //这里如果没有static,问题就大了:) static Derived* instance = nullptr; if (!instance) { instance = newDerived(); // Microsoft CRT extension. In an exe this this called after // winmain returns, in a dll is called in DLL_PROCESS_DETACH // 这个是MS的特权,在winmain返回或DLL_PROCESS_DETACH触发时调用注册的函数 _onexit(OnExit); } return instance; }
private: // this is the function that gets called by the CRT when the // process is shutting down. staticint __cdecl OnExit(){ // 防止退出后继续使用GetInstance?这个不是太懂 deleteGetInstance(); return0; } };
AutoLock
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// Automatically acquires and releases a lock when the object is // is destroyed. classAutoLock { public: // Acquires the lock. // 这个构造器是显式的,防止了某些情况下编译器自作聪明的CRITICAL_SECTION对象到AutoLock的转换。 explicitAutoLock(CRITICAL_SECTION* lock) : lock_(lock) { ::EnterCriticalSection(lock);//上锁 }
// Releases the lock; ~AutoLock() { ::LeaveCriticalSection(lock_); //释放锁}
// The traits class for Win32 handles that can be closed via CloseHandle() API. // 该类仅有3个public static函数,所以不会用于实例化 classHandleTraits { public: typedef HANDLE Handle;
// Generic wrapper for raw handles that takes care of closing handles // automatically. The class interface follows the style of // the ScopedFILE class with two additions: // - IsValid() method can tolerate multiple invalid handle values such as NULL // and INVALID_HANDLE_VALUE (-1) for Win32 handles. // - Set() (and the constructors and assignment operators that call it) // preserve the Windows LastError code. This ensures that GetLastError() can // be called after stashing a handle in a GenericScopedHandle object. Doing // this explicitly is necessary because of bug 528394 and VC++ 2015. // windows原生HANDLE的包裹,它会负责自动关闭句柄。 template <classTraits, classVerifier> classGenericScopedHandle { public: typedeftypename Traits::Handle Handle;
// // A smart pointer class for reference counted objects. Use this class instead // of calling AddRef and Release manually on a reference counted object to // avoid common memory leaks caused by forgetting to Release an object // reference. Sample usage: // // class MyFoo : public RefCounted<MyFoo> { // ... // private: // friend class RefCounted<MyFoo>; // Allow destruction by RefCounted<>. // ~MyFoo(); // Destructor must be private/protected. // }; // // void some_function() { // scoped_refptr<MyFoo> foo = MakeRefCounted<MyFoo>(); // foo->Method(param); // // |foo| is released when this function returns // } // // void some_other_function() { // scoped_refptr<MyFoo> foo = MakeRefCounted<MyFoo>(); // ... // foo = nullptr; // explicitly releases |foo| // ... // if (foo) // foo->Method(param); // } // // The above examples show how scoped_refptr<T> acts like a pointer to T. // Given two scoped_refptr<T> classes, it is also possible to exchange // references between the two objects, like so: // // { // scoped_refptr<MyFoo> a = MakeRefCounted<MyFoo>(); // scoped_refptr<MyFoo> b; // // b.swap(a); // // now, |b| references the MyFoo object, and |a| references nullptr. // } // // To make both |a| and |b| in the above example reference the same MyFoo // object, simply use the assignment operator: // // { // scoped_refptr<MyFoo> a = MakeRefCounted<MyFoo>(); // scoped_refptr<MyFoo> b; // // b = a; // // now, |a| and |b| each own a reference to the same MyFoo object. // } // // Also see Chromium's ownership and calling conventions: // https://chromium.googlesource.com/chromium/src/+/lkgr/styleguide/c++/c++.md#object-ownership-and-calling-conventions // Specifically: // If the function (at least sometimes) takes a ref on a refcounted object, // declare the param as scoped_refptr<T>. The caller can decide whether it // wishes to transfer ownership (by calling std::move(t) when passing t) or // retain its ref (by simply passing t directly). // In other words, use scoped_refptr like you would a std::unique_ptr except // in the odd case where it's required to hold on to a ref while handing one // to another component (if a component merely needs to use t on the stack // without keeping a ref: pass t as a raw T*). template <classT> classscoped_refptr { public: typedef T element_type;
// Constructs from raw pointer. constexpr if |p| is null. // 原生指针做参数的构造器 constexprscoped_refptr(T* p) : ptr_(p) { if (ptr_) AddRef(ptr_); }
// Copy constructor. This is required in addition to the copy conversion // constructor below. // 拷贝构造,直接中继原生指针构造 scoped_refptr(const scoped_refptr& r) : scoped_refptr(r.ptr_) {}
// Friend required for move constructors that set r.ptr_ to null. template <typename U> friendclassscoped_refptr; //移动构造器中对r.ptr置空,需要声明friend
// Non-inline helpers to allow: // class Opaque; // extern template class scoped_refptr<Opaque>; // Otherwise the compiler will complain that Opaque is an incomplete type. staticvoidAddRef(T* ptr); staticvoidRelease(T* ptr); };