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)