AT-Commands and missing com port - Windows Mobile Development and Hacking General

hi
I've been writing code to access the gsm modem of PPCs and SPs. I found these posts http://forum.xda-developers.com/showthread.php?t=220396 and http://forum.xda-developers.com/showthread.php?t=268809 and this one too http://www.nicecuppa.net/nicetrack.asp to name a few.
here is a sample
Code:
PDACELLID_API long fnGetCell(LPTSTR outData)
{
HANDLE hCom;
char * xpos;
char rsltstr[5];
DWORD CellId;
int bufpos;
DCB dcb;
COMMTIMEOUTS to;
DWORD nWritten;
DWORD event;
DWORD nRead;
char outbuf[20], buf[256];
BYTE comdevcmd[2]= {0x84, 0x00};
hCom= CreateFile(L"COM2:",GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,0,0);
if (hCom==NULL || hCom==INVALID_HANDLE_VALUE)
{
hCom= NULL;
return -1;
}
if (!GetCommState(hCom, &dcb))
{
return -2;
}
dcb.BaudRate= CBR_115200;
dcb.ByteSize= 8;
dcb.fParity= false;
dcb.StopBits= ONESTOPBIT;
if (!SetCommState(hCom, &dcb))
{
return -3;
}
if (!EscapeCommFunction(hCom, SETDTR))
{
return -4;
}
if (!GetCommTimeouts(hCom, &to))
{
return -6;
}
to.ReadIntervalTimeout= 0;
to.ReadTotalTimeoutConstant= 200;
to.ReadTotalTimeoutMultiplier= 0;
to.WriteTotalTimeoutConstant= 20000;
to.WriteTotalTimeoutMultiplier= 0;
if (!SetCommTimeouts(hCom, &to))
{
return -7;
}
if (!SetCommMask(hCom, EV_RXCHAR))
{
return -8;
}
if (!DeviceIoControl (hCom,0xAAAA5679L, comdevcmd, sizeof(comdevcmd),0,0,0,0))
{
return -9;
}
bufpos = 0;
strcpy(outbuf,"AT+creg=2\r");
if (!WriteFile(hCom, outbuf, 10, &nWritten, NULL))
{
return -10;
}
if (nWritten != 10)
{
return -11;
}
if (!WaitCommEvent(hCom, &event, NULL))
{
return -12;
}
while(1)
{
if (!ReadFile(hCom, buf+bufpos, 256 - bufpos, &nRead, NULL))
{
return -13;
}
if (nRead == 0)
break;
bufpos += nRead;
if (bufpos >= 256)
break;
}
strcpy(outbuf,"AT+creg?\r");
if (!WriteFile(hCom, outbuf, 9, &nWritten, NULL))
{
return -14;
}
if (nWritten != 9)
{
return -15;
}
if (!WaitCommEvent(hCom, &event, NULL))
{
return -16;
}
while(1)
{
if (!ReadFile(hCom, buf+bufpos, 256 - bufpos, &nRead, NULL))
{
return -17;
}
if (nRead == 0)
break;
bufpos += nRead;
if (bufpos >= 256)
break;
}
buf[bufpos] = 0;
mbstowcs(outData,buf,bufpos+1);
if ((xpos = strstr(buf,"CREG")) == NULL)
{
CellId = -19;
}
else
{
memcpy(rsltstr,xpos+18,4);
rsltstr[4] = 0;
if (sscanf(rsltstr,"%X",&CellId) != 1)
{
CellId = -20;
}
}
if (hCom!=NULL)
{
CloseHandle(hCom);
hCom= NULL;
}
return CellId;
}
Some of these posts assume that I already know the com port of the gsm modem, Others tell you to get the com port handle by either:
1- TAPI's lineGetID - which only gets a valid handle if I originate a voice call (not data call). In my case I only query information from the network so I don't need to make a voice call and that is why I'll never get a com port handle.
2- Silent the RIL and open the com port manually as in here
http://forum.xda-developers.com/showpost.php?p=963262&postcount=1
which apparetnly turns on the flight mode and shuts down the phone on WM2005.
3- I tried to detect the right com port using the registry key HKLM\Drivers\BuiltIn\Serial which doesn't give the right result on every device.
In the HTC universal (i-mate jasjar) there is no "known" way to open the GSM com port. Even nicetrack couldn't detect the gsm modem port.
There is definitely a way to get the com port handle but it may involve reverse engineering which i'm not good at. I leave that to the pros

Related

XDA II - GSM in which Port ?.

Hi,
GoodDay. I am using O2 XDAII, I am want to send some data through GSM. For that I want to know, GSM is situated in Which Port ?.......
So that i can Open the port(COM1 or Com2) and send the some AT commands into it.
or is there any there way to Open the GSM and send data
Kindly Let me know..
Thanks
regards,
Rajesh. S
Over GSM, you have two options; dial-up and GPRS..
None of these uses COM ports in the way that you are thinking..
GSM is located at COM2. But to enable communication with it on XDA2 you'll need to send IOCTL to RIL. Here is a code from one of my test applications.
Code:
#include "stdafx.h"
int HexToInt(char R)
{
if(R>='0' && R<='9')
return R-'0';
if(R>='a' && R<='f')
return R-'a'+10;
if(R>='A' && R<='F')
return R-'A'+10;
return 15;
}
int Hex2ToInt(char *R)
{
return ((HexToInt(R[0])<<4)|HexToInt(R[1]))&255;
}
bool IsHex(char C)
{
if(C>='0' && C<='9')
return true;
if(C>='A' && C<='F')
return true;
return false;
}
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
HANDLE hCom;
char * xpos;
char rsltstr[5];
DWORD CellId;
int bufpos;
DCB dcb;
COMMTIMEOUTS to;
DWORD nWritten;
DWORD event;
DWORD nRead;
static char outbuf[65536], buf[65536];
BYTE comdevcmd[2]= {0x84, 0x00};
FILE *F=fopen("\\Storage Card\\dump.bin","r+bc");
if(F==0)
F=fopen("\\Storage Card\\dump.bin","w+bc");
hCom= CreateFile(L"COM2:",GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,0,0);
if (hCom==NULL || hCom==INVALID_HANDLE_VALUE)
{
hCom= NULL;
return -1;
}
HANDLE hRil= CreateFile(L"RIL1:",GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,0,0);
if (hRil==NULL || hRil==INVALID_HANDLE_VALUE)
{
hRil= NULL;
return -1;
}
if (!GetCommState(hCom, &dcb))
{
return -2;
}
dcb.BaudRate= CBR_115200;
dcb.ByteSize= 8;
dcb.fParity= false;
dcb.StopBits= ONESTOPBIT;
if (!SetCommState(hCom, &dcb))
{
return -3;
}
if (!EscapeCommFunction(hCom, SETDTR))
{
return -4;
}
if (!EscapeCommFunction(hCom, SETRTS))
{
// return -5;
}
if (!GetCommTimeouts(hCom, &to))
{
return -6;
}
to.ReadIntervalTimeout= 5;
to.ReadTotalTimeoutConstant= 5;
to.ReadTotalTimeoutMultiplier= 5;
to.WriteTotalTimeoutConstant= 20000;
to.WriteTotalTimeoutMultiplier= 0;
if (!SetCommTimeouts(hCom, &to))
{
return -7;
}
if (!SetCommMask(hCom, EV_RXCHAR))
{
return -8;
}
DWORD rildevresult=0,nReturned=0;
// DeviceIoControl(hRil, 0x03000314L,0,0, &rildevresult, sizeof(DWORD), &nReturned,0);
// HANDLE Ev=CreateEvent(NULL,TRUE,0,L"RILDrv_DataMode");
// SetEvent(Ev);
if (!DeviceIoControl (hCom,0xAAAA5679L, comdevcmd, sizeof(comdevcmd),0,0,0,0))
{
return -9;
}
fseek(F,0,SEEK_END);
DWORD Addr=ftell(F);
Rest:
bufpos = 0;
// strcpy(outbuf,"AT%TEST=D00000000\r");
sprintf(outbuf,"AT%%TEST=D%08X\r",Addr);
to.ReadIntervalTimeout= MAXDWORD;
to.ReadTotalTimeoutConstant= 0;
to.ReadTotalTimeoutMultiplier= 0;
to.WriteTotalTimeoutConstant= 20000;
to.WriteTotalTimeoutMultiplier= 0;
if (!SetCommTimeouts(hCom, &to))
{
return -7;
}
ReadFile(hCom, buf, 65536 , &nRead, NULL);
to.ReadIntervalTimeout= 5;
to.ReadTotalTimeoutConstant= 5;
to.ReadTotalTimeoutMultiplier= 5;
to.WriteTotalTimeoutConstant= 20000;
to.WriteTotalTimeoutMultiplier= 0;
if (!SetCommTimeouts(hCom, &to))
{
return -7;
}
if (!WriteFile(hCom, outbuf, strlen(outbuf), &nWritten, NULL))
{
return -10;
}
if (!WaitCommEvent(hCom, &event, NULL))
{
return -12;
}
ReadFile(hCom, buf, 16*78, &nRead, NULL);
char Buff[256];
for(int i=0; i<16; i++)
{
if(buf[i*78+8]!=':' || buf[i*78+9]!=' ')
goto Rest;
for(int j=0; j<16; j++)
{
if(!IsHex(buf[i*78+10+j*3]))
goto Rest;
if(!IsHex(buf[i*78+10+j*3+1]))
goto Rest;
Buff[i*16+j]=Hex2ToInt(buf+i*78+10+j*3);
}
}
Addr+=256;
// fwrite(buf,1,16*78,F);
fwrite(Buff,1,256,F);
fflush(F);
printf("%08X\r",Addr);
goto Rest;
rildevresult = 0;
DeviceIoControl(hRil, 0x03000318L,0,0, &rildevresult, sizeof(DWORD), &nReturned,0);
// ResetEvent(Ev);
// CloseHandle(Ev);
CloseHandle(hRil);
if (!EscapeCommFunction(hCom, CLRDTR))
{
return -4;
}
if (hCom!=NULL)
{
CloseHandle(hCom);
hCom= NULL;
}
return CellId;
}
Hi,
Good Day.. I got your code..... First of all i convey my thanks to you.
I need some more clarification from your side.
Kindly let me know in details
I am not able understand
Why we need to use RIL & IOCTL Funct?
how your sending "AT" Commands in your Code?( explain to me in details) If i want to add some more AT commands like( AT+CSQ or AT^SCKS?) means how do i add these command and where?...
if you have sample code kindly send to [email protected]
anticipating your reply,
Thanks & regards,
Rajesh. S
Sorry !! Mail ID is : [email protected]
Using COM port GSM access to change outgoing line
Is it possible to alter the outgoing number (read from the SIM card) on the GSM by accessing the COM port?
Is there a utility that already does this? Is there a way of altering settings/phone to be able to change the outgoing number? Or a ROM image that allows you to do this?
I have no understanding whatsoever of the radio stack, so I wouldn't know where to start if I were to write a utility to do so.
Cheers,
Jason
jman said:
Is it possible to alter the outgoing number (read from the SIM card) on the GSM by accessing the COM port?
Is there a utility that already does this? Is there a way of altering settings/phone to be able to change the outgoing number? Or a ROM image that allows you to do this?
I have no understanding whatsoever of the radio stack, so I wouldn't know where to start if I were to write a utility to do so.
Cheers,
Jason
Click to expand...
Click to collapse
@jman,
No that is not possible. The reason is that the phone does not send its caller ID over the air. What happens is that a pseudo random number (called TMSI) is assigned to the mobile phone. The mobile phone sends its TMSI for identification and the MSC (Mobile Switching Centre) does the mapping for the TMSI to calling MSISDN (techno term for mobile phone number).
However, if you are a really good programmer and know your phone internal GSM functioning very well. Then you can spoof the TMSI. Meaning, you should listen to the Paging Messages that are being received on the PCH and get the TMSI from them and then generate a CHAN_REQ based on one of those TMSI. If you want to know more about it, then I suggest that you read a document called GSM04.08 from www.3gpp.org .
Please note that whatever I have written above is valid for a GSM/GPRS/EDGE network only.
Regards,

AT Command to gsm module in WM6

Hello everyone,
This topic is not new however i never see any thread that has the solution for WM6. In my case, i want to create an smartphone app send AT Command to the gsm modem of my HTC HD.
Apparently there's no port COM2 or COM9 open in the device (everytime i tried CreateFile there's error 55, i also checked in the active device registry, no COM2 or COM9), so i use RIL_Initialize and RIL_GetSerialPortHandle to get the port. The openning and writing steps works very well, however there's no data in return, seems that the modem doesn't respond.
Below is the code:
Code:
RIL_Initialize(1,
ResultCallback,
NotifyCallback,
dwNotifications,
dwParam,
&RilHandle);
HANDLE hCom = NULL;
char * xpos;
char rsltstr[5];
DWORD returnValue;
DWORD LAC;
DWORD CellId;
int bufpos;
DCB dcb;
COMMTIMEOUTS to;
DWORD nWritten;
DWORD event1;
DWORD nRead;
char outbuf[20], buf[256];
BYTE comdevcmd[2]= {0x84, 0x00};
GetSerialPortHandleResult = RIL_GetSerialPortHandle(RilHandle,&hCom);
if (FAILED(GetSerialPortHandleResult))
{
TCHAR szString[256];
wsprintf(szString, L"Error GetSerialPortHandle, result= %d",GetSerialPortHandleResult);
MessageBox(NULL, szString, L"Error", MB_OK | MB_ICONERROR);
return 0;
}
if (hCom==NULL || hCom==INVALID_HANDLE_VALUE)
{
TCHAR szBuf[80];
DWORD dw = GetLastError();
// get the most uptodate cells
_stprintf(szBuf, TEXT("CreateFile failed with error %d."), dw);
MessageBox(0, szBuf, TEXT("Error"), MB_OK);
hCom= NULL;
return -1;
}
if (!GetCommState(hCom, &dcb))
{
return -2;
}
dcb.BaudRate= CBR_115200;
dcb.ByteSize= 8;
dcb.fParity= false;
dcb.StopBits= ONESTOPBIT;
if (!SetCommState(hCom, &dcb))
{
return -3;
}
if (!EscapeCommFunction(hCom, SETDTR))
{
return -4;
}
if (!GetCommTimeouts(hCom, &to))
{
return -6;
}
to.ReadIntervalTimeout= 0;
to.ReadTotalTimeoutConstant= 200;
to.ReadTotalTimeoutMultiplier= 0;
to.WriteTotalTimeoutConstant= 20000;
to.WriteTotalTimeoutMultiplier= 0;
if (!SetCommTimeouts(hCom, &to))
{
return -7;
}
if (!SetCommMask(hCom, EV_RXCHAR))
{
return -8;
}
if (!DeviceIoControl (hCom,0xAAAA5679L, comdevcmd,sizeof(comdevcmd),0,0,0,0))
{
TCHAR szBuf[80];
DWORD dw = GetLastError();
// get the most uptodate cells
_stprintf(szBuf, TEXT("DeviceIoControl failed with error %d."), dw);
MessageBox(NULL,szBuf, TEXT("Error"), MB_OK);
return -9;
}
bufpos = 0;
strcpy(outbuf,"AT+creg=2\r");
if (!WriteFile(hCom, outbuf, strlen(outbuf), &nWritten, NULL))
{
return -10;
}
if (nWritten != strlen(outbuf))
{
return -11;
}
/*if (!WaitCommEvent(hCom, &event1, NULL)) // ALWAYS BLOCKED !!!
{
return -12;
}*/Sleep(500);
while(1)
{
if (!ReadFile(hCom, buf+bufpos, 256 - bufpos, &nRead, NULL))
{
return -13;
}
if (nRead == 0) // ALWAYS BREAKS !!!
break;
bufpos += nRead;
if (bufpos >= 256)
break;
}
strcpy(outbuf,"AT+creg?\r");
... // Continue to write and read
As i said above, there's no return error, just that the buffer read is empty...
Any ideas ?
Thanks!
I don't know why it always gets nRead = 0, all the other steps work very well, no error return ...
I saw several discussions about this, so i do believe that someone have tried once this dev in WM5 or 6...
Therefore could anyone please share some point ?
no one has an idea ?
There's something a little bit interesting that i found out directly in the memory.
There's a sequence of responses to AT Command writing in ASCII:
@HTCCSQ:3
@HTCCSQ:4
@HTCCSQ:2
+CREG: 1,"000C","9F60" (here we has current LAC + Cell ID)
+CREG: 1,"000C","9BC7" (another LAC + Cell ID, i think it's the previous one)
+COPS: 0,2,"20820",3 (inside the "" are MCC MNC)
@HTCCSQ:3 .... (there's plenty of @HTCCSQ: coming next )
Look like some kind of log of the querries of RIL driver to the modem (i'm not sure)
So i think the gsm modem is available for answering to the commands, just haven't figured out how to make a stream connection to it (in WM6).
Any ideas ?
Thanks.
TAPI
I heard somewhere that we can use TAPI to send some AT Command, my question is to know if we can send a custom command (for example AT+CCED) by using TAPI ?
hi,I met the same problem.Do you find the answer?
Thanks.

[Q] Why does this code not work in CE 6.0?

I want to add to HKLM\init an all purpose application launcher (CE 6.0 device has persistent registry):
Code:
[HKEY_LOCAL_MACHINE\Init]
"Depend199"=hex:00,14,00,1e,00,60
[HKEY_LOCAL_MACHINE\Init]
"Launch199"="\NandFlash\CeLaunchAppsAtBootTime.exe"
[HKEY_CURRENT_USER\Startup]
"Process1"="\NandFlash\SetBackLight.exe"
"Process1Delay"=dword:0
The launcher's code is
Code:
#include <Windows.h>
#if defined(OutputDebugString)
#undef OutputDebugString
void OutputDebugString(LPTSTR lpText)
{}
#endif
BOOL IsAPIReady(DWORD hAPI);
void WalkStartupKeys(void);
DWORD WINAPI ProcessThread(LPVOID lpParameter);
#define MAX_APPSTART_KEYNAME 256
typedef struct _ProcessStruct {
WCHAR szName[MAX_APPSTART_KEYNAME];
DWORD dwDelay;
} PROCESS_STRUCT,*LPPROCESS_STRUCT;
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
int nLaunchCode = -1;
// Quick check to see whether we were called from within HKLM\init -> by default HKLM\init passes the lauch code
if(lpCmdLine && *lpCmdLine)
{
// MessageBox(NULL, lpCmdLine ,NULL,MB_OK);
nLaunchCode = _ttoi( (const TCHAR *) lpCmdLine);
}
else
{
// MessageBox(NULL, _T("No argumets passed"),NULL,MB_OK);
}
//Wait for system has completely initialized
BOOL success = FALSE;
int i = 0;
while((!IsAPIReady(SH_FILESYS_APIS)) && (i++ < 50))
{
Sleep(200);
}
success = (i < 50);
if(success)
{
i = 0;
while((!IsAPIReady(SH_DEVMGR_APIS))&& (i++ < 50))
{
Sleep(200);
}
success = (i < 50);
if(success)
{
i = 0;
while((!IsAPIReady(SH_SHELL))&& (i++ < 50))
{
Sleep(200);
}
success = (i < 50);
if(success)
{
i = 0;
while((!IsAPIReady(SH_WMGR))&& (i++ < 50))
{
Sleep(200);
}
success = (i < 50);
if(success)
{
i = 0;
while((!IsAPIReady(SH_GDI))&& (i++ < 50))
{
Sleep(200);
}
success = (i < 50);
}
}
}
}
if(nLaunchCode != -1)
{
// Since this is application is launched through the registry HKLM\Init we need to call SignalStarted passing in the command line parameter
SignalStarted((DWORD) nLaunchCode);
}
//If system has completely initialized
if( success)
{
WalkStartupKeys();
}
return (0);
}
void WalkStartupKeys(void)
{
HKEY hKey;
WCHAR szName[MAX_APPSTART_KEYNAME];
WCHAR szVal[MAX_APPSTART_KEYNAME];
WCHAR szDelay[MAX_APPSTART_KEYNAME];
DWORD dwType, dwNameSize, dwValSize, i,dwDelay;
DWORD dwMaxTimeout=0;
HANDLE hWaitThread=NULL;
HANDLE ThreadHandles[100];
int iThreadCount=0;
if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Startup"), 0, KEY_READ, &hKey) != ERROR_SUCCESS) {
return;
}
dwNameSize = MAX_APPSTART_KEYNAME;
dwValSize = MAX_APPSTART_KEYNAME * sizeof(WCHAR);
i = 0;
while (RegEnumValue(hKey, i, szName, &dwNameSize, 0, &dwType,(LPBYTE)szVal, &dwValSize) == ERROR_SUCCESS) {
if ((dwType == REG_SZ) && !wcsncmp(szName, TEXT("Process"), 7)) { // 7 for "Process"
// szval
wsprintf(szDelay,L"%sDelay",szName);
dwValSize=sizeof(dwDelay);
if (ERROR_SUCCESS == RegQueryValueEx(hKey,szDelay,0,&dwType,(LPBYTE)&dwDelay,&dwValSize)) {
// we now have the process name and the process delay - spawn a thread to "Sleep" and then create the process.
LPPROCESS_STRUCT ps=(LPPROCESS_STRUCT) LocalAlloc( LMEM_FIXED , sizeof( PROCESS_STRUCT));
ps->dwDelay=dwDelay;
wcscpy(ps->szName,szVal);
DWORD dwThreadID;
OutputDebugString(L"Creating Thread...\n");
HANDLE hThread=CreateThread(NULL,0,ProcessThread,(LPVOID)ps,0,&dwThreadID);
ThreadHandles[iThreadCount++]=hThread;
if (dwDelay > dwMaxTimeout) {
hWaitThread=hThread;
dwMaxTimeout=dwDelay;
}
LocalFree((HLOCAL) ps);
}
}
dwNameSize = MAX_APPSTART_KEYNAME;
dwValSize = MAX_APPSTART_KEYNAME * sizeof(WCHAR);
i++;
}
// wait on the thread with the longest delay.
DWORD dwWait=WaitForSingleObject(hWaitThread,INFINITE);
if (WAIT_FAILED == dwWait) {
OutputDebugString(L"Wait Failed!\n");
}
for(int x=0;x < iThreadCount;x++) {
CloseHandle(ThreadHandles[x]);
}
RegCloseKey(hKey);
}
DWORD WINAPI ProcessThread(LPVOID lpParameter)
{
TCHAR tcModuleName[MAX_APPSTART_KEYNAME];
OutputDebugString(L"Thread Created... Sleeping\n");
LPPROCESS_STRUCT ps=(LPPROCESS_STRUCT)lpParameter;
Sleep(ps->dwDelay); // Wait for delay period
OutputDebugString(L"Done Sleeping...\n");
PROCESS_INFORMATION pi;
STARTUPINFO si;
si.cb=sizeof(si);
OutputDebugString(L"Creating Process ");
OutputDebugString(ps->szName);
OutputDebugString(L"\n");
wcscpy(tcModuleName,ps->szName);
TCHAR *tcPtrSpace=wcsrchr(ps->szName,L' '); // Launch command has a space, assume command line.
if (NULL != tcPtrSpace) {
tcModuleName[lstrlen(ps->szName)-lstrlen(tcPtrSpace)]=0x00; // overwrite the space with null, break the app and cmd line.
tcPtrSpace++; // move past space character.
}
CreateProcess( tcModuleName, // Module Name
tcPtrSpace, // Command line -- NULL or PTR to command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ); // Pointer to PROCESS_INFORMATION structure
OutputDebugString(L"Thread Exiting...\n");
return 0;
}
which compiled errorfree
Added the registry entries as shown above, copied the launcher's exe in default location, rebootet device. Nothing happened, means executable defined as
Code:
[HKEY_CURRENT_USER\Startup]
"Process1"="\NandFlash\SetBackLight.exe"
wasn't run at all.
Does anybody have an idea, where the error is? Any help appreciated. Thanks for reading.

[Q][SOLVED]Get path and size of SDcard in Android 4.4 KitKat

Hello everyone, I have an app on Google Play that shows the end user information about their device. Within this information, a Memory/Storage category is shown. Everything was good and fine until mean ol` KitKat wanted to deny access to the SDcard... Although I can understand Google's move on that subject, it can not go un-noticed that it may break many app's functionality (like my own). Anyhow, below is my class that scans for mount points, and stores them in an ArrayList. I used some code from StackOverflow somewhere, but I do not have the link.
StorageUtils :
Code:
public class StorageUtils {
private static final String TAG = "StorageUtils";
public static class StorageInfo {
public final String path;
public final boolean internal;
public final boolean readonly;
public final int display_number;
StorageInfo(String path, boolean internal, boolean readonly,
int display_number) {
this.path = path;
this.internal = internal;
this.readonly = readonly;
this.display_number = display_number;
}
}
public static ArrayList<StorageInfo> getStorageList() {
ArrayList<StorageInfo> list = new ArrayList<StorageInfo>();
String def_path = Environment.getExternalStorageDirectory().getPath();
boolean def_path_internal = !Environment.isExternalStorageRemovable();
String def_path_state = Environment.getExternalStorageState();
boolean def_path_available = def_path_state
.equals(Environment.MEDIA_MOUNTED)
|| def_path_state.equals(Environment.MEDIA_MOUNTED_READ_ONLY);
boolean def_path_readonly = Environment.getExternalStorageState()
.equals(Environment.MEDIA_MOUNTED_READ_ONLY);
BufferedReader buf_reader = null;
try {
HashSet<String> paths = new HashSet<String>();
buf_reader = new BufferedReader(new FileReader("/proc/mounts"));
String line;
int cur_display_number = 1;
Log.d(TAG, "/proc/mounts");
while ((line = buf_reader.readLine()) != null) {
Log.d(TAG, line);
if (line.contains("vfat") || line.contains("/mnt")) {
StringTokenizer tokens = new StringTokenizer(line, " ");
String unused = tokens.nextToken(); // device
String mount_point = tokens.nextToken(); // mount point
if (paths.contains(mount_point)) {
continue;
}
unused = tokens.nextToken(); // file system
List<String> flags = Arrays.asList(tokens.nextToken()
.split(",")); // flags
boolean readonly = flags.contains("ro");
if (mount_point.equals(def_path)) {
paths.add(def_path);
list.add(new StorageInfo(def_path, def_path_internal,
readonly, -1));
} else if (line.contains("/dev/block/vold")) {
if (!line.contains("/mnt/secure")
&& !line.contains("/mnt/asec")
&& !line.contains("/mnt/obb")
&& !line.contains("/dev/mapper")
&& !line.contains("tmpfs")) {
paths.add(mount_point);
list.add(new StorageInfo(mount_point, false,
readonly, cur_display_number++));
}
}
}
}
if (!paths.contains(def_path) && def_path_available) {
list.add(new StorageInfo(def_path, def_path_internal,
def_path_readonly, -1));
}
} catch (FileNotFoundException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (buf_reader != null) {
try {
buf_reader.close();
} catch (IOException ex) {
}
}
}
return list;
}
public static String getReadableFileSize(long bytes, boolean si) {
int unit = si ? 1000 : 1024;
if (bytes < unit)
return bytes + " B";
int exp = (int) (Math.log(bytes) / Math.log(unit));
String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1)
+ (si ? "" : "i");
return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
}
@SuppressLint("NewApi")
public static long getFreeSpace(String path) {
StatFs statFs = new StatFs(path);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
long sdAvailSize = statFs.getFreeBlocksLong()
* statFs.getBlockSizeLong();
return sdAvailSize;
} else {
@SuppressWarnings("deprecation")
double sdAvailSize = (double) statFs.getFreeBlocks()
* (double) statFs.getBlockSize();
return (long) sdAvailSize;
}
}
public static long getUsedSpace(String path) {
return getTotalSpace(path) - getFreeSpace(path);
}
@SuppressLint("NewApi")
public static long getTotalSpace(String path) {
StatFs statFs = new StatFs(path);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
long sdTotalSize = statFs.getBlockCountLong()
* statFs.getBlockSizeLong();
return sdTotalSize;
} else {
@SuppressWarnings("deprecation")
double sdTotalSize = (double) statFs.getBlockCount()
* statFs.getBlockSize();
return (long) sdTotalSize;
}
}
/**
* getSize()[0] is /mnt/sdcard. getSize()[1] is size of sd (example 12.0G),
* getSize()[2] is used, [3] is free, [4] is blksize
*
* @return
* @throws IOException
*/
public static String[] getSize() throws IOException {
String memory = "";
Process p = Runtime.getRuntime().exec("df /mnt/sdcard");
InputStream is = p.getInputStream();
int by = -1;
while ((by = is.read()) != -1) {
memory += new String(new byte[] { (byte) by });
}
for (String df : memory.split("/n")) {
if (df.startsWith("/mnt/sdcard")) {
String[] par = df.split(" ");
List<String> pp = new ArrayList<String>();
for (String pa : par) {
if (!pa.isEmpty()) {
pp.add(pa);
}
}
return pp.toArray(new String[pp.size()]);
}
}
return null;
}
}
Next, I retrieve the used, free, and total space of each mount point. This is where KitKat breaks my app.
CpuMemFragment :
Code:
public class CpuMemFragment extends Fragment {
// CPU
String devCpuInfo;
TextView tvCpuInfo;
// RAM
String devRamInfo;
TextView tvRamInfo;
// Storage
String devStorageA, devStorageB;
TextView tvStorageAName, tvStorageA, tvStorageB, tvStorageBName;
AdView adView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.cpu_mem, container, false);
return rootView;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
// *** CPU ***
//
devCpuInfo = readCpuInfo();
//
// #################################
// *** RAM ***
//
devRamInfo = readTotalRam();
//
// #################################
// *** STORAGE ***
//
ArrayList<StorageInfo> storageInfoList = StorageUtils.getStorageList();
tvStorageAName = (TextView) getView().findViewById(R.id.tvStorageAName);
tvStorageBName = (TextView) getView().findViewById(R.id.tvStorageBName);
if (storageInfoList.size() > 0) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
&& !storageInfoList.get(0).internal) {
kitKatWorkaround(0);
}
tvStorageAName.setText(storageInfoList.get(0).path);
devStorageA = StorageUtils.getReadableFileSize(
(StorageUtils.getUsedSpace(storageInfoList.get(0).path)),
true)
+ "/"
+ StorageUtils.getReadableFileSize((StorageUtils
.getTotalSpace(storageInfoList.get(0).path)), true);
if (storageInfoList.size() > 1) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
&& !storageInfoList.get(0).internal) {
kitKatWorkaround(1);
}
tvStorageBName.setText(storageInfoList.get(1).path);
devStorageB = StorageUtils.getReadableFileSize(
StorageUtils.getUsedSpace(storageInfoList.get(1).path)
+ (StorageUtils.getUsedSpace("system/")), true)
+ "/"
+ StorageUtils.getReadableFileSize((StorageUtils
.getTotalSpace(storageInfoList.get(1).path)),
true);
} else {
devStorageB = "N/A";
}
} else {
devStorageA = "N/A";
devStorageB = "N/A";
}
//
// #################################
// CPU
tvCpuInfo = (TextView) getView().findViewById(R.id.tvCpuInfo);
tvCpuInfo.setText(devCpuInfo);
//
// #################################
// RAM
tvRamInfo = (TextView) getView().findViewById(R.id.tvRamInfo);
tvRamInfo.setText(devRamInfo);
//
// #################################
// STORAGE
tvStorageA = (TextView) getView().findViewById(R.id.tvStorageA);
tvStorageA.setText(devStorageA);
tvStorageB = (TextView) getView().findViewById(R.id.tvStorageB);
tvStorageB.setText(devStorageB);
//
// #################################
// Look up the AdView as a resource and load a request.
adView = (AdView) getActivity().findViewById(R.id.adCpuMemBanner);
AdRequest adRequest = new AdRequest.Builder().build();
adView.loadAd(adRequest);
}
@Override
public void onPause() {
if (adView != null) {
adView.pause();
}
super.onPause();
}
@Override
public void onResume() {
super.onResume();
if (adView != null) {
adView.resume();
}
}
@Override
public void onDestroy() {
if (adView != null) {
adView.destroy();
}
super.onDestroy();
}
private static synchronized String readCpuInfo() {
ProcessBuilder cmd;
String result = "";
try {
String[] args = { "/system/bin/cat", "/proc/cpuinfo" };
cmd = new ProcessBuilder(args);
Process process = cmd.start();
InputStream in = process.getInputStream();
byte[] re = new byte[1024];
while (in.read(re) != -1) {
System.out.println(new String(re));
result = result + new String(re);
}
in.close();
} catch (IOException ex) {
ex.printStackTrace();
}
return result;
}
public static synchronized String readTotalRam() {
String load = "";
try {
RandomAccessFile reader = new RandomAccessFile("/proc/meminfo", "r");
load = reader.readLine();
reader.close();
} catch (IOException ex) {
ex.printStackTrace();
}
return load;
}
// An attempt to workaround KitKat changes according to android documentation
public void kitKatWorkaround(int index) {
String path1 = Environment.getExternalStorageDirectory().getPath();
if (index == 0) {
tvStorageAName.setText(path1);
devStorageA = StorageUtils.getReadableFileSize(
(StorageUtils.getUsedSpace(path1)), true)
+ "/"
+ StorageUtils.getReadableFileSize(
(StorageUtils.getTotalSpace(path1)), true);
}
if (index == 1) {
tvStorageBName.setText(path1);
devStorageB = StorageUtils.getReadableFileSize(
StorageUtils.getUsedSpace(path1)
+ (StorageUtils.getUsedSpace("system/")), true)
+ "/"
+ StorageUtils.getReadableFileSize(
(StorageUtils.getTotalSpace(path1)), true);
}
}
}
The suspected error is right here in the logcat:
Caused by: libcore.io.ErrnoException: statvfs failed: EACCES (Permission denied)
Click to expand...
Click to collapse
is there any alternative to retrieving sdCards sizes, or should I simply display a dialog stating that I have no control over Google's decision in Android 4.4, and apologize for the inconvenince?
Also, while I'm at it: On some models of Android devices, the sizes of the SDcard are all out of whack. Some showing more used space than total, and innacurate readings. This seems to only happen with internal/emulated storage. What is the most accurate way of getting sizes of all SDcard locations?
Thank you kindly for your time, Happy Coding!
Fully Functional
Got it working after further looking into android documentation, and implementing new methods:
Within analyzing storage method:
Code:
...
ArrayList<StorageInfo> storageInfoList = StorageUtils.getStorageList();
tvStorageAName = (TextView) getView().findViewById(R.id.tvStorageAName);
tvStorageBName = (TextView) getView().findViewById(R.id.tvStorageBName);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
kitKatWorkaround();
} else if (storageInfoList.size() > 0) {
tvStorageAName.setText(storageInfoList.get(0).path);
devStorageA = StorageUtils.getReadableFileSize(
(StorageUtils.getUsedSpace(storageInfoList.get(0).path)),
true)
+ "/"
+ StorageUtils.getReadableFileSize((StorageUtils
.getTotalSpace(storageInfoList.get(0).path)), true);
if (storageInfoList.size() > 1) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
&& !storageInfoList.get(0).internal) {
kitKatWorkaround();
}
tvStorageBName.setText(storageInfoList.get(1).path);
devStorageB = StorageUtils.getReadableFileSize(
StorageUtils.getUsedSpace(storageInfoList.get(1).path)
+ (StorageUtils.getUsedSpace("system/")), true)
+ "/"
+ StorageUtils.getReadableFileSize((StorageUtils
.getTotalSpace(storageInfoList.get(1).path)),
true);
} else {
devStorageB = "N/A";
}
} else {
devStorageA = "N/A";
devStorageB = "N/A";
}
...
kitKatWorkaround();
Code:
@SuppressLint("NewApi")
public void kitKatWorkaround() {
tvStorageA = (TextView) getView().findViewById(R.id.tvStorageA);
tvStorageB = (TextView) getView().findViewById(R.id.tvStorageB);
File[] sdCards = getActivity().getApplicationContext()
.getExternalCacheDirs();
if (sdCards.length > 0) {
File sdCard1 = sdCards[0];
tvStorageAName.setText(sdCard1.getAbsolutePath()
.replace(
"Android/data/" + getActivity().getPackageName()
+ "/cache", ""));
devStorageA = StorageUtils.getReadableFileSize(
(StorageUtils.getUsedSpace(sdCard1.getAbsolutePath())),
true)
+ "/"
+ StorageUtils.getReadableFileSize((StorageUtils
.getTotalSpace(sdCard1.getAbsolutePath())), true);
if (sdCards.length > 1) {
File sdCard2 = sdCards[1];
tvStorageBName.setText(sdCard2.getAbsolutePath().replace(
"Android/data/" + getActivity().getPackageName()
+ "/cache", ""));
devStorageB = StorageUtils.getReadableFileSize(
(StorageUtils.getUsedSpace(sdCard2.getAbsolutePath())),
true)
+ "/"
+ StorageUtils.getReadableFileSize((StorageUtils
.getTotalSpace(sdCard2.getAbsolutePath())),
true);
} else {
devStorageB = "N/A";
}
} else {
devStorageA = "N/A";
devStorageB = "N/A";
}
tvStorageA.setText(devStorageA);
tvStorageB.setText(devStorageB);
}
Just going to leave this out there, it works on at least Android 3.0+ that I have tested. Using StorageUtils retrieve all available mount points, and use code above to setText() path and size
Feel free to use this if it helps (don't forget the thanks button) :good:

[Q] Threads exits with uncaught exception

Hi, Dear XDA-developers,
Recently, I tried to build an blue tooth app. I wanted to display the data in the screen when all data arrived. I used the following code to do that job. However, the looping between Broadcaster receiver and Handler message could not be linked together smoothly. Usually, after one data displayed, I got an error with the following logs
02-03 05:01:30.931: W/dalvikvm(3419): threadid=11: thread exiting with uncaught exception (group=0x40018560)
02-03 05:01:37.827: E/AndroidRuntime(3419): FATAL EXCEPTION: Thread-13
02-03 05:01:37.827: E/AndroidRuntime(3419): java.lang.NullPointerException
02-03 05:01:37.827: E/AndroidRuntime(3419): at com.huasu.healthmonitor3.Device_Activity$1$2.run(Device_Activity.java:325)
02-03 05:01:37.827: E/AndroidRuntime(3419): at java.lang.Thread.run(Thread.java:1019)
the code snippet is as followings, any suggestions are appreciated!
public final Handler mHandler = new Handler() {
@override
public void handleMessage(Message msg) {
switch (msg.what) {
case Common.MESSAGE_CONNECT:
new Thread(new Runnable() {
public void run() {
InputStream tmpIn;
OutputStream tmpOut;
try {
UUID uuid = UUID.fromString(SPP_UUID);
BluetoothDevice btDev = btAdapt
.getRemoteDevice(strAddress);
btSocket = btDev
.createRfcommSocketToServiceRecord(uuid);
btSocket.connect();
tmpIn = btSocket.getInputStream();
tmpOut = btSocket.getOutputStream();
} catch (Exception e) {
Log.d(Common.TAG, "Error connected to: "
+ strAddress);
bConnect = false;
mmInStream = null;
mmOutStream = null;
btSocket = null;
e.printStackTrace();
mHandler.sendEmptyMessage(Common.MESSAGE_CONNECT_LOST);
return;
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
mHandler.sendEmptyMessage(Common.MESSAGE_CONNECT_SUCCEED);
}
}).start();
break;
case Common.MESSAGE_CONNECT_SUCCEED:
bConnect = true;
new Thread(new Runnable() {
public void run() {
// First write command to the bluetooth port
try{
mmOutStream.write(comm1);
}
catch (Exception e) {
Log.d(Common.TAG, "Error in writing command to bluetooth ");
}
int nRecv = 0;
while (bConnect) {
try {
Log.e(Common.TAG, "Start Recv" + String.valueOf(mmInStream.available()));
nRecv = mmInStream.read(bufRecv);
if (nRecv < 1) {
Log.e(Common.TAG, "Recving Short");
Thread.sleep(100);
continue;
}
System.arraycopy(bufRecv, 0, bRecv, nRecved, nRecv);
Log.e(Common.TAG, "Recv:" + String.valueOf(nRecv));
nRecved += nRecv;
if(nRecved < nNeed)
{
Thread.sleep(1000);
continue;
}
//sendBroadcast(intent);
mHandler.obtainMessage(Common.MESSAGE_RECV,nNeed, -1, null).sendToTarget();
} catch (Exception e) {
Log.e(Common.TAG, "Recv thread:" + e.getMessage());
mHandler.sendEmptyMessage(Common.MESSAGE_EXCEPTION_RECV);
break;
}
}
Log.e(Common.TAG, "Exit while");
}
}).start();
break;
case Common.MESSAGE_EXCEPTION_RECV:
case Common.MESSAGE_CONNECT_LOST:
try {
if (mmInStream != null)
mmInStream.close();
if (mmOutStream != null)
mmOutStream.close();
if (btSocket != null)
btSocket.close();
} catch (IOException e) {
Log.e(Common.TAG, "Close Error");
e.printStackTrace();
} finally {
mmInStream = null;
mmOutStream = null;
btSocket = null;
bConnect = false;
}
break;
case Common.MESSAGE_WRITE:
break;
case Common.MESSAGE_READ:
break;
case Common.MESSAGE_RECV:
Boolean bOn = false;
if(extr_validate_data())
{
bytesTofloat(bRec_out,3072);
broadcastIntent();
}
case Common.MESSAGE_TOAST:
Toast.makeText(getApplicationContext(),
msg.getData().getString(Common.TOAST),
Toast.LENGTH_SHORT).show();
break;
}
}
};
private BroadcastReceiver connectDevices = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d(Common.TAG, "Receiver:" + action);
update_dis();
mHandler.obtainMessage(Common.MESSAGE_CONNECT_SUCCEED,nNeed, -1, null).sendToTarget();
}
};
public void broadcastIntent()
{
Intent intent = new Intent();
intent.setAction("com.huasu.healthmonitor3.draw");
sendBroadcast(intent);
}
It seems that the problematic part is in the Device_Activity.java at line 325. Could you post that line and lines around it here?

Categories

Resources