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)
