Kaizener 的工具箱
Being Kaizener.
2017年5月25日 星期四
2017年2月16日 星期四
[Android] UnsatisfiedLinkError
症狀
E/AndroidRuntime: FATAL EXCEPTION: Thread-3056
Process: com.perfectcorp.beautycircle, PID: 14917
java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.perfectcorp.beautycircle-1/base.apk"],nativeLibraryDirectories=[/data/app/com.perfectcorp.beautycircle-1/lib/arm64, /data/app/com.perfectcorp.beautycircle-1/base.apk!/lib/arm64-v8a, /vendor/lib64, /system/lib64]]] couldn't find "libweibosdkcore.so"
at java.lang.Runtime.loadLibrary(Runtime.java:367)
at java.lang.System.loadLibrary(System.java:1076)
at com.sina.weibo.sdk.net.HttpManager.(SourceFile:83)
at com.sina.weibo.sdk.net.NetUtils.internalHttpRequest(SourceFile:46)
at com.sina.weibo.sdk.utils.AidTask.loadAidFromNet(SourceFile:344)
at com.sina.weibo.sdk.utils.AidTask.access$3(SourceFile:331)
at com.sina.weibo.sdk.utils.AidTask$2.run(SourceFile:203)
at java.lang.Thread.run(Thread.java:818)
線索
- 這問題發生在 Nexus 9 的機器上,HTC Nexus 9 是一台 ARM64 的機器
- java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.perfectcorp.beautycircle-1/base.apk"],nativeLibraryDirectories=[/data/app/com.perfectcorp.beautycircle-1/lib/arm64, /data/app/com.perfectcorp.beautycircle-1/base.apk!/lib/arm64-v8a, /vendor/lib64, /system/lib64]]] couldn't find "libweibosdkcore.so"
解法
- Root cause 在於 Nexus 9 是 ARM64 的機器,但 libweibosdkcore.so 卻只有 x86。
- 為了解決這問題,解法會是指定 .so 的目錄
- 在 app gradle 的 defaultConfig 加上 ndk { abiFilters "armeabi-v7a" }
- 在 project的根目錄下,找到 gradle.properties (不存在則新建)"android.useDeprecatedNdk=true 指定目錄",不讓系统自動找.so檔
Reference
2012年1月9日 星期一
[C++] Mutex
1. 同一個時間內只能夠有一個執行緒擁有mutex。
2. 同一個時間內只能夠有一個執行緒進入critical section。
3. Mutex速度較慢。因為Critical Section不需要進入OS核心,直接在User Mode 就可以進行動作。
4. Mutex可以跨Process使用。Critical Section則只能夠在同一個Process使用。
5. 等待一個mutex時,你可以指定『結束等待』時間長度,但對於critical section則不行。
用CreateMutex來產生Mutex
HANDLE WINAPI CreateMutex( __in_opt LPSECURITY_ATTRIBUTES lpMutexAttributes, __in BOOL bInitialOwner, __in_opt LPCTSTR lpName ); // The name can have a "Global\" or "Local\" prefix to explicitly create the object in the global or session namespace. The remainder of the name can contain any character except the backslash character (\).用ReleaseMutex來釋放Mutex
BOOL WINAPI ReleaseMutex( __in HANDLE hMutex );簡單的範例
CMutex::CMutex(std::wstring wstrMutexName)
{
std::wstring wstrMutex = L"Global\\";
wstrMutex += wstrMutexName;
m_mutex = ::CreateMutex(NULL, FALSE, wstrMutex.c_str());
}
CMutex::~CMutex()
{
::CloseHandle(m_mutex);
}
HRESULT CMutex::Lock()
{
HRESULT hr = E_FAIL;
DWORD dRet = WaitForSingleObject(m_mutex, INFINITE);
switch (dRet)
{
case WAIT_TIMEOUT: // Time out
break;
case WAIT_OBJECT_0: // Process over
hr = S_OK;
break;
case WAIT_OBJECT_0 + 1: // Don't Know
break;
}
return hr;
}
void CMutex::Unlock()
{
::ReleaseMutex(m_mutex);
}
如果想要利用Mutex讓一個Process在同一時間只被執行一次的話,可以用下列的方法檢查1.Mutex的Create是否有Error
CMutex g_vthumbMutex(strModuleName);
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
return;
}
2. 用OpenMutex
HANDLE WINAPI OpenMutex( __in DWORD dwDesiredAccess, __in BOOL bInheritHandle, __in LPCTSTR lpName );Reference:
[C++] Enumerate file in directory.
bool findFileInDir(wchar_t* rootDir)
{
wchar_t fname[BUFFSIZE];
ZeroMemory(fname, BUFFSIZE);
WIN32_FIND_DATA fd;
ZeroMemory(&fd, sizeof(WIN32_FIND_DATA));
HANDLE hSearch;
wchar_t filePathName[BUFFSIZE];
wchar_t tmpPath[BUFFSIZE];
ZeroMemory(filePathName, BUFFSIZE);
ZeroMemory(tmpPath, BUFFSIZE);
wcscpy(filePathName, rootDir);
BOOL bSearchFinished = FALSE;
if( filePathName[wcslen(filePathName) -1] != L'\\' )
{
wcscat(filePathName, L"\\");
}
wcscat(filePathName, L"*");
hSearch = FindFirstFile(filePathName, &fd);
//Is directory
if( (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
&& wcscmp(fd.cFileName, L".") && wcscmp(fd.cFileName, L"..") )
{
wcscpy(tmpPath, rootDir);
wcscat(tmpPath, fd.cFileName);
wcscat(tmpPath, L"\\");
findFileInDir(tmpPath);
}
else if( wcscmp(fd.cFileName, L".") && wcscmp(fd.cFileName, L"..") )
{
wsprintf(fname, L"%ls%ls", rootDir, fd.cFileName);
DEBUG_MSG((L"[findFileInDir] filename: %ls", fname));
}
while( !bSearchFinished )
{
if( FindNextFile(hSearch, &fd) )
{
if( (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
&& wcscmp(fd.cFileName, L".") && wcscmp(fd.cFileName, L"..") )
{
wcscpy(tmpPath, rootDir);
wcscat(tmpPath, fd.cFileName);
wcscat(tmpPath, L"\\");
findFileInDir(tmpPath);
}
else if( wcscmp(fd.cFileName, L".") && wcscmp(fd.cFileName, L"..") )
{
wsprintf(fname, L"%ls%ls", rootDir, fd.cFileName);
DEBUG_MSG((L"[findFileInDir] filename: %ls", fname));
}
}
else
{
if( GetLastError() == ERROR_NO_MORE_FILES ) //Normal Finished
{
bSearchFinished = TRUE;
}
else
bSearchFinished = TRUE; //Terminate Search
}
}
FindClose(hSearch);
return true;
}
[C++] How to get free disk space
int getFreeSpace(wstring wstrWorkingFolder)
{
int nFreeSpace = 0;
HINSTANCE hModule = ::LoadLibrary(L"KERNEL32.DLL");
if(hModule)
{
PFNGETDISKFREESPACEEX pDiskFreeSpaceEx = NULL;
// Determine function to use
pDiskFreeSpaceEx = reinterpret_cast(::GetProcAddress(hModule, "GetDiskFreeSpaceExA"));
if(!pDiskFreeSpaceEx)
{
DWORD dwSectorsPerCluster = 0;
DWORD dwBytesPerSector = 0;
DWORD dwFreeClusters = 0;
DWORD dwClusters = 0;
if(::GetDiskFreeSpace(wstrWorkingFolder.c_str(), &dwSectorsPerCluster, &dwBytesPerSector, &dwFreeClusters, &dwClusters) == TRUE)
{
nFreeSpace = dwFreeClusters * dwBytesPerSector * dwSectorsPerCluster;
}
}
else
{
ULARGE_INTEGER uliFreeBytesAvailableToCaller;
ULARGE_INTEGER uliTotalNumberOfBytes;
ULARGE_INTEGER uliTotalNumberOfFreeBytes;
if(::GetDiskFreeSpaceEx(wstrWorkingFolder.c_str(), &uliFreeBytesAvailableToCaller, &uliTotalNumberOfBytes, &uliTotalNumberOfFreeBytes) == TRUE)
{
nFreeSpace = static_cast<__int64>(uliFreeBytesAvailableToCaller.QuadPart / (1024 * 1024));
}
}
// Release library
::FreeLibrary(hModule);
}
return nFreeSpace;
}
[C++] Check Process
bool CheckProcess(wstring wstrExeName)
{
bool bHasProcess = false;
unsigned long aProcesses[1024], cbNeeded, cProcesses;
if(EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
{
cProcesses = cbNeeded / sizeof(unsigned long);
for(unsigned int i = 0; i < cProcesses; i++)
{
if(aProcesses[i] == 0)
continue;
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, aProcesses[i]);
wchar_t buffer[50];
GetModuleBaseNameW(hProcess, 0, buffer, 50);
CloseHandle(hProcess);
if(wstrExeName == wstring(buffer))
{
bHasProcess = true;
break;
}
}
}
return bHasProcess;
}
[C++] Kill Process
bool KillProcess(wstring wstrExename)
{
bool bOK = false;
WCHAR wszCmd[2048];
int nSize = 160;
PROCESS_INFORMATION pi;
STARTUPINFOW si;
ZeroMemory(&si, sizeof(STARTUPINFOW));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFOW);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
swprintf(wszCmd, L"taskkill /F /IM %s", wstrExename.c_str());
if (CreateProcessW(NULL, wszCmd, NULL, NULL, FALSE, CREATE_NEW_CONSOLE|IDLE_PRIORITY_CLASS, NULL, NULL, &si, &pi))
{
int nKillWaitTime = 30000;
int nRet = WaitForSingleObject(pi.hProcess, nKillWaitTime);
switch (nRet)
{
case WAIT_TIMEOUT: // Time out
break;
case WAIT_OBJECT_0: // Process over
break;
case WAIT_OBJECT_0 + 1: // Don't Know
break;
}
CloseHandle(pi.hProcess);
pi.hProcess = NULL;
CloseHandle(pi.hThread);
pi.hThread = NULL;
bOK = true;
}
return bOK;
}
訂閱:
意見 (Atom)