2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
19 * @file FSysRuntimeInfo.cpp
20 * @brief This is the implementation file for _RuntimeInfoImpl class.
23 * This file contains the implementation of _RuntimeInfoImpl class.
26 #include <unique_ptr.h>
33 #include <app_storage.h>
35 #include <runtime_info.h>
38 #include <FBaseRtEvent.h>
39 #include <FBaseRtIEventArg.h>
40 #include <FBaseRtIEventListener.h>
41 #include <FBaseRtThread.h>
42 #include <FBaseSysLog.h>
43 #include <FApp_AppInfo.h>
44 #include <FBase_StringConverter.h>
45 #include <FSys_EnvironmentImpl.h>
46 #include <FSys_RuntimeInfoImpl.h>
48 using namespace Tizen::App;
49 using namespace Tizen::Base;
50 using namespace Tizen::Base::Runtime;
54 namespace Tizen { namespace System
57 static const wchar_t* _ALLOCATED_MEMORY = L"AllocatedMemory";
58 static const wchar_t* _MEMORY_ALLOCATED = L"http://tizen.org/runtime/memory.allocated";
60 static const wchar_t* _AVAILABLE_EXTERNAL_STORAGE = L"AvailableExternalStorage";
61 static const wchar_t* _STORAGE_AVAILABLE_EXTERNAL = L"http://tizen.org/runtime/storage.available.external";
63 static const wchar_t* _AVAILABLE_INTERNAL_STORAGE = L"AvailableInternalStorage";
64 static const wchar_t* _STORAGE_AVAILABLE_INTERNAL = L"http://tizen.org/runtime/storage.available.internal";
66 static const wchar_t* _AVAILABLE_MEDIA_STORAGE = L"AvailableMediaStorage";
67 static const wchar_t* _STORAGE_AVAILABLE_INTERNAL_MEDIA = L"http://tizen.org/runtime/storage.available.internal.media";
69 static const wchar_t* _BATTERY_LEVEL = L"BatteryLevel";
70 static const wchar_t* _CHARGING = L"IsCharging";
72 static const wchar_t* _CPU_CORE_ALL_USAGE = L"http://tizen.org/runtime/cpu.core.all.usage";
74 static const wchar_t* _MAX_ALLOCATABLE_MEMORY = L"MaxAllocatableMemory";
75 static const wchar_t* _AVAILABLE_VIDEO_MEMORY = L"AvailableVideoMemory";
76 static const wchar_t* _ALLOCATED_VIDEO_MEMORY = L"AllocatedVideoMemory";
77 static const wchar_t* _AVAILABLE_MEMORY = L"AvailableMemory";
78 static const wchar_t* _MEMORY_AVAILABLE = L"http://tizen.org/runtime/memory.available";
79 static const wchar_t* _MEMORY_AVAILABLE_VIDEO = L"http://tizen.org/runtime/memory.available.video";
80 static const wchar_t* _MEMORY_ALLOCATED_VIDEO = L"http://tizen.org/runtime/memory.allocated.video";
82 static const wchar_t* _STORAGE_ALLOCATED_INTERNAL_APPLICATION = L"http://tizen.org/runtime/storage.allocated.internal.application";
83 static const wchar_t* _STORAGE_ALLOCATED_INTERNAL_AUDIO = L"http://tizen.org/runtime/storage.allocated.internal.audio";
84 static const wchar_t* _STORAGE_ALLOCATED_INTERNAL_VIDEO = L"http://tizen.org/runtime/storage.allocated.internal.video";
85 static const wchar_t* _STORAGE_ALLOCATED_INTERNAL_IMAGE = L"http://tizen.org/runtime/storage.allocated.internal.image";
86 static const wchar_t* _STORAGE_ALLOCATED_INTERNAL_DOWNLOAD = L"http://tizen.org/runtime/storage.allocated.internal.download";
87 static const wchar_t* _STORAGE_ALLOCATED_EXTERNAL_APPLICATION = L"http://tizen.org/runtime/storage.allocated.external.application";
88 static const wchar_t* _STORAGE_ALLOCATED_EXTERNAL_AUDIO = L"http://tizen.org/runtime/storage.allocated.external.audio";
89 static const wchar_t* _STORAGE_ALLOCATED_EXTERNAL_VIDEO = L"http://tizen.org/runtime/storage.allocated.external.video";
90 static const wchar_t* _STORAGE_ALLOCATED_EXTERNAL_IMAGE = L"http://tizen.org/runtime/storage.allocated.external.image";
91 static const wchar_t* _STORAGE_ALLOCATED_EXTERNAL_DOWNLOAD = L"http://tizen.org/runtime/storage.allocated.external.download";
93 static const int _RUNTIME_INFO_EVENT_TYPE_INT = 101;
94 static const int _RUNTIME_INFO_EVENT_TYPE_LONGLONG = 102;
97 static const char* const _PROC_SYSTEM_MEMORY_INFO = "/proc/meminfo";
98 static const char* const _PROC_PROCESS_MEMORY_INFO = "/proc/self/status";
99 static const char* const _PROC_STAT = "/proc/stat";
101 static const char* const _PROC_KEY_SYSTEM_MEMORY_TOTAL = "MemTotal";
102 static const char* const _PROC_KEY_SYSTEM_MEMORY_FREE = "MemFree";
103 static const char* const _PROC_KEY_PROCESS_MEMORY = "VmSize";
105 static const char* const _ROOT_PATH = "/";
106 static const char* const _STORAGE_PATH = "/opt/storage/sdcard";
107 static const char* const _MEDIA_PATH = "/opt/usr/media";
108 static const char* const _INTERNAL_PATH = "/opt";
110 static const int _MAX_BUFFER_LENGTH = 1024;
112 static const int _CPU_USAGE_EVALUATION_INTERVAL = 1000000; //1 sec
116 unsigned long long user;
117 unsigned long long system;
118 unsigned long long nice;
119 unsigned long long idle;
120 unsigned long long wait;
121 unsigned long long hi;
122 unsigned long long si;
123 unsigned long long zero;
126 bool read_proc_stat(procstat_t *p)
131 fp = fopen(_PROC_STAT, "r");
137 ret = fscanf(fp, "%s %llu %llu %llu %llu %llu %llu %llu %llu",
165 void diff_proc_stat(procstat_t *a, procstat_t *b, procstat_t *d)
167 d->user = a->user - b->user;
168 d->system = a->system - b->system;
169 d->nice = a->nice - b->nice;
170 d->idle = a->idle - b->idle;
171 d->wait = a->wait - b->wait;
172 d->hi = a->hi - b->hi;
173 d->si = a->si - b->si;
174 d->zero = a->zero - b->zero;
177 class _RuntimeInfoEventArg : public IEventArg
180 _RuntimeInfoEventArg()
184 , errorCode(E_SUCCESS)
185 , DirectoryPath(null)
190 ~_RuntimeInfoEventArg()
192 if(DirectoryPath != null)
194 delete [] DirectoryPath;
200 long long longLongValue;
203 IEventListener* pListener;
206 class _RuntimeInfoEvent : public Event
209 void FireImpl(IEventListener& listener, const IEventArg& arg)
211 const _RuntimeInfoEventArg* runtimeArg = dynamic_cast<const _RuntimeInfoEventArg*> (&arg);
213 if(runtimeArg == null)
215 SysLogException(NID_SYS, E_SYSTEM, "Argument is null.");
219 switch(runtimeArg->Type)
221 case _RUNTIME_INFO_EVENT_TYPE_INT:
223 IRuntimeInfoGetIntAsyncResultListener* pIntListener = dynamic_cast<IRuntimeInfoGetIntAsyncResultListener*>(&listener);
225 if(pIntListener == runtimeArg->pListener)
227 pIntListener->OnResultReceivedForGetValueAsync(runtimeArg->intValue, runtimeArg->errorCode);
228 RemoveListener(listener);
233 case _RUNTIME_INFO_EVENT_TYPE_LONGLONG:
235 IRuntimeInfoGetLonglongAsyncResultListener* pLonglongListener = dynamic_cast<IRuntimeInfoGetLonglongAsyncResultListener*>(&listener);
236 if(pLonglongListener == runtimeArg->pListener)
238 pLonglongListener->OnResultReceivedForGetValueAsync(runtimeArg->longLongValue, runtimeArg->errorCode);
239 RemoveListener(listener);
240 delete pLonglongListener;
248 _RuntimeInfoEvent runtimeInfoEvent;
250 _RuntimeInfoImpl::_RuntimeInfoImpl(void)
254 _RuntimeInfoImpl::~_RuntimeInfoImpl(void)
259 _RuntimeInfoImpl::GetValue(const String& key, String& value)
261 return E_OBJ_NOT_FOUND;
265 _RuntimeInfoImpl::GetValue(const String& key, int& value)
269 result r = E_OBJ_NOT_FOUND;
271 if (key == _BATTERY_LEVEL)
273 return GetBatteryLevel(value);
275 else if (key == _ALLOCATED_MEMORY || key == _ALLOCATED_VIDEO_MEMORY)
277 r = GetFromProc(_PROC_PROCESS_MEMORY_INFO, _PROC_KEY_PROCESS_MEMORY, free_size);
278 SysTryReturnResult(NID_SYS, r == E_SUCCESS, E_SYSTEM, "It is failed to get memory size.");
279 value = free_size * 1024;
281 else if (key == _AVAILABLE_MEMORY || key == _AVAILABLE_VIDEO_MEMORY || key == _MAX_ALLOCATABLE_MEMORY || key == _MEMORY_AVAILABLE || key == _MEMORY_AVAILABLE_VIDEO)
283 r = GetFromProc(_PROC_SYSTEM_MEMORY_INFO, _PROC_KEY_SYSTEM_MEMORY_FREE, free_size);
284 SysTryReturnResult(NID_SYS, r == E_SUCCESS, E_SYSTEM, "It is failed to get memory size.");
285 value = free_size * 1024;
287 else if (key == _MEMORY_ALLOCATED || key == _MEMORY_ALLOCATED_VIDEO)
289 r = GetFromProc(_PROC_SYSTEM_MEMORY_INFO, _PROC_KEY_SYSTEM_MEMORY_TOTAL, total_size);
290 SysTryReturnResult(NID_SYS, r == E_SUCCESS, E_SYSTEM, "It is failed to get memory size.");
291 r = GetFromProc(_PROC_SYSTEM_MEMORY_INFO, _PROC_KEY_SYSTEM_MEMORY_FREE, free_size);
292 SysTryReturnResult(NID_SYS, r == E_SUCCESS, E_SYSTEM, "It is failed to get memory size.");
293 value = (total_size - free_size) * 1024;
299 _RuntimeInfoImpl::GetDirectorySize(const char* path)
306 char command[512] = {0,};
310 sprintf(command, "du -sk -P %s >> /tmp/size_of_directory.tmp", path);
312 system("rm -rf /tmp/size_of_directory.tmp");
316 pFile = fopen("/tmp/size_of_directory.tmp", "r");
321 ret = fscanf(pFile, "%lld", &size);
337 system("rm -rf /tmp/size_of_directory.tmp");
342 _RuntimeInfoImpl::GetValue(const String& key, long long& value)
345 long long total_size = 0;
346 long long free_size =0;
347 result r = E_OBJ_NOT_FOUND;
349 if (key == _MEMORY_AVAILABLE || key == _MEMORY_AVAILABLE_VIDEO)
351 r = GetFromProcLonglong(_PROC_SYSTEM_MEMORY_INFO, _PROC_KEY_SYSTEM_MEMORY_FREE, free_size);
352 SysTryReturnResult(NID_SYS, r == E_SUCCESS, E_SYSTEM, "It is failed to get memory size.");
353 value = free_size * 1024;
355 else if (key == _MEMORY_ALLOCATED || key == _MEMORY_ALLOCATED_VIDEO)
357 r = GetFromProcLonglong(_PROC_SYSTEM_MEMORY_INFO, _PROC_KEY_SYSTEM_MEMORY_TOTAL, total_size);
358 SysTryReturnResult(NID_SYS, r == E_SUCCESS, E_SYSTEM, "It is failed to get memory size.");
359 r = GetFromProcLonglong(_PROC_SYSTEM_MEMORY_INFO, _PROC_KEY_SYSTEM_MEMORY_FREE, free_size);
360 SysTryReturnResult(NID_SYS, r == E_SUCCESS, E_SYSTEM, "It is failed to get memory size.");
361 value = (total_size - free_size) * 1024;
363 else if (key == _AVAILABLE_INTERNAL_STORAGE)
365 return GetAvailableInternalStorage(value);
367 else if (key == _AVAILABLE_EXTERNAL_STORAGE)
369 return GetAvailableExternalStorage(value);
371 else if (key == _AVAILABLE_MEDIA_STORAGE)
373 return GetAvailableMediaStorage(value);
375 else if(key == _STORAGE_AVAILABLE_INTERNAL)
377 return GetAvailableInternalStorage(value);
379 else if(key == _STORAGE_AVAILABLE_EXTERNAL)
381 return GetAvailableExternalStorage(value);
383 else if(key == _STORAGE_AVAILABLE_INTERNAL_MEDIA)
385 return GetAvailableMediaStorage(value);
391 _RuntimeInfoImpl::GetValue(const String& key, double& value)
393 return E_OBJ_NOT_FOUND;
397 _RuntimeInfoImpl::GetValue(const String& key, bool& value)
399 if (key == _CHARGING)
401 return IsChargingMode(value);
405 return E_OBJ_NOT_FOUND;
410 _RuntimeInfoImpl::GetValue(const String& key, UuId& value)
412 return E_OBJ_NOT_FOUND;
416 _RuntimeInfoImpl::GetBatteryLevel(int& value)
418 int batteryValue = -1;
419 batteryValue = device_get_battery_pct();
420 SysTryReturnResult(NID_SYS, !(batteryValue < 0 || value > 100), E_SYSTEM, "[E_SYSTEM] device_get_battery_pct return %d", batteryValue);
421 value = batteryValue;
427 _RuntimeInfoImpl::IsChargingMode(bool& value)
429 bool chargeState = false;
431 ret = runtime_info_get_value_bool(RUNTIME_INFO_KEY_BATTERY_IS_CHARGING, &chargeState);
432 SysTryReturnResult(NID_SYS, ret == 0, E_SYSTEM, "[E_SYSTEM] runtime_info_get_value_bool returns %d.", ret);
439 _RuntimeInfoImpl::GetAvailableInternalStorage(long long& value)
443 result r = E_SUCCESS;
445 r = GetCapacity(_ROOT_PATH, total, temp);
446 SysTryReturn(NID_SYS, !IsFailed(r), E_SYSTEM, r, "[E_SYSTEM] system error has occurred. ");
450 r = GetCapacity(_INTERNAL_PATH, total, temp);
451 SysTryReturn(NID_SYS, !IsFailed(r), E_SYSTEM, r, "[E_SYSTEM] system error has occurred. ");
458 _RuntimeInfoImpl::GetAvailableExternalStorage(long long& value)
460 int sdCardStatus = 0;
464 ret = vconf_get_int(VCONFKEY_SYSMAN_MMC_STATUS, &sdCardStatus);
465 SysTryReturn(NID_SYS, !(ret < 0), E_SYSTEM, E_SYSTEM, "[E_SYSTEM] vconf_get_int VCONFKEY_SYSMAN_MMC_STATUS failed");
467 if(sdCardStatus == 0)
473 return GetCapacity(_STORAGE_PATH, total, value);
477 _RuntimeInfoImpl::GetAvailableMediaStorage(long long& value)
480 return GetCapacity(_MEDIA_PATH, total, value);
484 _RuntimeInfoImpl::GetCapacity(const char* path, long long& totalSize, long long& availableSize)
487 if (statfs(path, &fs) < 0)
489 SysLogException(NID_SYS, E_SYSTEM, "[E_SYSTEM] statfs() failed");
493 totalSize = static_cast< long long >(fs.f_bsize) * static_cast< long long >(fs.f_blocks);
494 availableSize = static_cast< long long >(fs.f_bsize) * static_cast< long long >(fs.f_bavail);
500 _RuntimeInfoImpl::GetFromProcLonglong(const char* path, const char* key, long long& value)
502 FILE* pStream = null;
503 char line[_MAX_BUFFER_LENGTH] = {0, };
504 char fieldName[_MAX_BUFFER_LENGTH] = {0, };
505 long long keyValue = 0;
506 pStream = fopen(path, "r");
507 SysTryReturnResult(NID_SYS, pStream != null, E_SYSTEM, "%s open is failed.", path);
509 while (fgets(line, sizeof(line), pStream))
511 if (sscanf(line, "%s %lld %*s", fieldName, &keyValue) == 2)
513 if (strncmp(fieldName, key, static_cast< int >(strlen(key))) == 0)
523 SysLogException(NID_SYS, E_OBJ_NOT_FOUND, "it can't find %s field", key);
524 return E_OBJ_NOT_FOUND;
528 _RuntimeInfoImpl::GetFromProc(const char* path, const char* key, int& value)
530 FILE* pStream = null;
531 char line[_MAX_BUFFER_LENGTH] = {0, };
532 char fieldName[_MAX_BUFFER_LENGTH] = {0, };
534 pStream = fopen(path, "r");
535 SysTryReturnResult(NID_SYS, pStream != null, E_SYSTEM, "%s open is failed.", path);
537 while (fgets(line, sizeof(line), pStream))
539 if (sscanf(line, "%s %d %*s", fieldName, &keyValue) == 2)
541 if (strncmp(fieldName, key, static_cast< int >(strlen(key))) == 0)
551 SysLogException(NID_SYS, E_OBJ_NOT_FOUND, "it can't find %s field", key);
552 return E_OBJ_NOT_FOUND;
556 _RuntimeInfoImpl::GetDirectorySizeAsync(void* data)
562 _RuntimeInfoEventArg* pEventArg = (_RuntimeInfoEventArg*)data;
563 long long size = _RuntimeInfoImpl::GetDirectorySize(pEventArg->DirectoryPath);
565 if(pEventArg == null)
567 SysLogException(NID_SYS, E_OUT_OF_MEMORY, "It is failed to create instance of _RuntimeInfoEventArg");
570 pEventArg->Type = _RUNTIME_INFO_EVENT_TYPE_LONGLONG;
571 pEventArg->longLongValue = size;
572 SysLog(NID_SYS, "Fire event %x %s %lld", pEventArg, pEventArg->DirectoryPath, size);
573 runtimeInfoEvent.Fire(*pEventArg);
579 _RuntimeInfoImpl::GetCpuUsageAsync(void* data)
581 result r = E_SUCCESS;
584 procstat_t first, second, diffrence;
585 unsigned long long total, usage;
587 if(read_proc_stat(&first) != false)
589 usleep(_CPU_USAGE_EVALUATION_INTERVAL);
590 if(read_proc_stat(&second) != false)
592 diff_proc_stat(&second, &first, &diffrence);
593 total = diffrence.user + diffrence.system
594 + diffrence.nice + diffrence.idle
595 + diffrence.wait + diffrence.hi
597 usage = 10000 - (diffrence.idle * 10000 / total);
611 _RuntimeInfoEventArg* pEventArg = (_RuntimeInfoEventArg*) data;
612 if(pEventArg == null)
614 SysLogException(NID_SYS, E_OUT_OF_MEMORY, "It is failed to create instance of _RuntimeInfoEventArg");
617 pEventArg->errorCode = r;
618 pEventArg->Type = _RUNTIME_INFO_EVENT_TYPE_INT;
619 pEventArg->intValue = value;
621 runtimeInfoEvent.Fire(*pEventArg);
627 _RuntimeInfoImpl::GetValueAsync(const String& key, IRuntimeInfoGetIntAsyncResultListener* listener)
629 result r = E_SUCCESS;
631 SysTryReturnResult(NID_SYS, listener != null, E_INVALID_ARG, "listener is null");
633 if (key == _CPU_CORE_ALL_USAGE)
637 SysLog(NID_SYS, "%x", listener);
638 runtimeInfoEvent.AddListener(*listener, false);
643 _RuntimeInfoEventArg* pEventArg = new (std::nothrow) _RuntimeInfoEventArg();
644 pEventArg->pListener = listener;
645 thr_id = pthread_create(&p_thread, null, GetCpuUsageAsync, pEventArg);
646 pthread_detach(p_thread);
650 SysLogException(NID_SYS, E_INVALID_ARG, "Required key[%ls] is not valid", key.GetPointer());
657 _RuntimeInfoImpl::GetValueAsync(const String& key, IRuntimeInfoGetLonglongAsyncResultListener* listener)
661 result r = E_SUCCESS;
662 char* directoryPath = null;
664 SysTryReturnResult(NID_SYS, listener != null, E_INVALID_ARG, "listener is null");
666 if(key == _STORAGE_ALLOCATED_INTERNAL_APPLICATION)
668 directoryPath = _StringConverter::CopyToCharArrayN(_EnvironmentImpl::GetPredefinedPath(PREDEFINED_DIRECTORY_APPLICATIONS));
670 else if (key == _STORAGE_ALLOCATED_INTERNAL_AUDIO)
672 directoryPath = _StringConverter::CopyToCharArrayN(_EnvironmentImpl::GetPredefinedPath(PREDEFINED_DIRECTORY_SOUNDS));
674 else if (key == _STORAGE_ALLOCATED_INTERNAL_VIDEO)
676 directoryPath = _StringConverter::CopyToCharArrayN(_EnvironmentImpl::GetPredefinedPath(PREDEFINED_DIRECTORY_VIDEOS));
678 else if (key == _STORAGE_ALLOCATED_INTERNAL_IMAGE)
680 directoryPath = _StringConverter::CopyToCharArrayN(_EnvironmentImpl::GetPredefinedPath(PREDEFINED_DIRECTORY_IMAGES));
682 else if (key == _STORAGE_ALLOCATED_INTERNAL_DOWNLOAD)
684 directoryPath = _StringConverter::CopyToCharArrayN(_EnvironmentImpl::GetPredefinedPath(PREDEFINED_DIRECTORY_DOWNLOADS));
686 else if (key == _STORAGE_ALLOCATED_EXTERNAL_APPLICATION)
688 directoryPath = _StringConverter::CopyToCharArrayN(_EnvironmentImpl::GetPredefinedPath(PREDEFINED_DIRECTORY_EXTERNAL_APPLICATIONS));
690 else if (key == _STORAGE_ALLOCATED_EXTERNAL_AUDIO)
692 directoryPath = _StringConverter::CopyToCharArrayN(_EnvironmentImpl::GetPredefinedPath(PREDEFINED_DIRECTORY_EXTERNAL_SOUNDS));
694 else if (key == _STORAGE_ALLOCATED_EXTERNAL_VIDEO)
696 directoryPath = _StringConverter::CopyToCharArrayN(_EnvironmentImpl::GetPredefinedPath(PREDEFINED_DIRECTORY_EXTERNAL_VIDEOS));
698 else if (key == _STORAGE_ALLOCATED_EXTERNAL_IMAGE)
700 directoryPath = _StringConverter::CopyToCharArrayN(_EnvironmentImpl::GetPredefinedPath(PREDEFINED_DIRECTORY_EXTERNAL_IMAGES));
703 else if (key == _STORAGE_ALLOCATED_EXTERNAL_DOWNLOAD)
705 directoryPath = _StringConverter::CopyToCharArrayN(_EnvironmentImpl::GetPredefinedPath(PREDEFINED_DIRECTORY_EXTERNAL_DOWNLOADS));
709 SysLogException(NID_SYS, E_INVALID_ARG, "Required key[%ls] is not valid", key.GetPointer());
713 SysLog(NID_SYS, "%s", GetErrorMessage(r));
714 SysLog(NID_SYS, "%s", directoryPath);
719 SysLog(NID_SYS, "test %x", listener);
720 runtimeInfoEvent.AddListener(*listener);
723 _RuntimeInfoEventArg* pEventArg = new (std::nothrow) _RuntimeInfoEventArg();
724 pEventArg->pListener = listener;
725 pEventArg->DirectoryPath = directoryPath;
727 thr_id = pthread_create(&p_thread, null, GetDirectorySizeAsync, pEventArg);
728 SysLog(NID_SYS, "%d", thr_id);
729 pthread_detach(p_thread);
736 _RuntimeInfoImpl::GetInstance(RuntimeInfo& runtimeinfo)
738 return runtimeinfo.__pRuntimeInfoImpl;
741 const _RuntimeInfoImpl*
742 _RuntimeInfoImpl::GetInstance(const RuntimeInfo& runtimeinfo)
744 return runtimeinfo.__pRuntimeInfoImpl;