How to check IOException cause on the catch?
Is e.getCause().getMessage() always returns the same string on all the android versions and devices for the same cause? Is it a good approach to check if IOException's cause is android.system.ErrnoException: write failed: ENOSPC (No space left on device) for checking if the user's device is out of space on that specific drive?
try {
// Here I'm writing a file with OutputStream
} catch (IOException e) {
// Check if IOException cause equals android.system.ErrnoException: write failed: ENOSPC (No space left on device)
} finally {
}
It is not usually a good idea to rely on error messages as they might vary with OS versions.
If targeting API level 21 or above, there is an elegant way to find the actual root cause of the IOException based on an error code. (ENOSPC in your case)
https://developer.android.com/reference/android/system/OsConstants#ENOSPC
It may be checked like this:
catch (IOException e) {
if (e.getCause() instanceof ErrnoException) {
int errorNumber = ((ErrnoException) e.getCause()).errno;
if (errorNumber == OsConstants.ENOSPC) {
// Out of space
}
}
}
errno is a public field in https://developer.android.com/reference/android/system/ErrnoException
Related
This might be a basic question but I cannot find an answer. When you want to catch only FileNotFound in Android, then you write
} catch (FileNotFoundException e) {
But what do you write if you want to catch exactly ENOSPC (No space left on device) errors? I can't use "catch (Exception e)" because I want to explicitly deal with this one error.
You cannot do so directly as enospc is signaled as a java.io.IOException which will catch many other io related issues as well. But by looking up the cause and the error it's signalling you can zoom in and handle enospc exceptions but rethrow all others, like this:
} catch (IOException ex) {
boolean itsanenospcex = false;
// make sure the cause is an ErrnoException
if (ex.getCause() instanceof android.system.ErrnoException) {
// if so, we can get to the causing errno
int errno = ((android.system.ErrnoException) ex.getCause()).errno;
// and check for the appropriate value
itsanenospcex = errno == OsConstants.ENOSPC;
}
if (itsanenospcex) {
// handle it
} else {
// if it's any other ioexception, rethrow it
throw ex;
}
}
Sidenote: } catch (Exception e) { is generally considered bad practice.
Is there a way to log the binary data send to the tranceive method of a NFC tag? https://developer.android.com/reference/android/nfc/tech/NfcV.html#transceive(byte[])
I am trying to find the last few missing pieces in a protocol and it would help if I could listen to the data getting sent.
I'm guessing that:
You want to monitor the APDUs/bytes sent from an app you have installed.
You've already searched for info about that specific protocol and found nothing.
At the Logcat, no relevant info is shown (by default).
Looking up at the transceive source code
public byte[] transceive(byte[] data) throws IOException {
return transceive(data, true);
}
which redirects to:
byte[] transceive(byte[] data, boolean raw) throws IOException {
checkConnected();
try {
TransceiveResult result = mTag.getTagService().transceive(mTag.getServiceHandle(),
data, raw);
if (result == null) {
throw new IOException("transceive failed");
} else {
return result.getResponseOrThrow();
}
} catch (RemoteException e) {
Log.e(TAG, "NFC service dead", e);
throw new IOException("NFC service died");
}
}
Which goes on to the TransceiveResult class.
My best bet (if you wish to get to the very end) is to recompile an Android source code that prints out the data input'd to the byte[] transceive(byte[] data) function. Good luck.
EDIT: Another option I happened to realise is to use an APDU sniffer, although I legitimately don't know how legal this option is.
I'm using usb-serial-for-android library and I am getting some strange results. After 2.5 hours of continuous communicating with the serial port and reading and writing successfully, I get this exception:
exception in UsbManager.openDevice
android.os.TransactionTooLargeException
at android.os.BinderProxy.transact(Native Method)
at android.hardware.usb.IUsbManager$Stub$Proxy.openDevice(IUsbManager.java:339)
at android.hardware.usb.UsbManager.openDevice(UsbManager.java:255)
at com.hoho.android.usbserial.driver.UsbSerialProber$1.probe(UsbSerialProber.java:63)
at com.hoho.android.usbserial.driver.UsbSerialProber.probeSingleDevice(UsbSerialProber.java:174)
But when i force close my app and then restart it, everything is fine and my app can communicate with the port again.
It maybe useful to mention that before the exception , I get this exception:
java.io.FileNotFoundException: /sdcard/log.txt: open failed: EMFILE (Too many open files)
at libcore.io.IoBridge.open(IoBridge.java:406)
at java.io.FileOutputStream.<init>(FileOutputStream.java:88)
at java.io.FileWriter.<init>(FileWriter.java:58)
at org.example.myapp.util.L.log(L.java:32)
I use class L for logging purposes:
public class L {
public synchronized void log(String message){
File logFile = new File("sdcard/log.txt");
if (!logFile.exists())
{
try
{
logFile.createNewFile();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try
{
//BufferedWriter for performance, true to set append to file flag
BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true));
buf.append(new Date(DateProvider.getInstance().getCurrentDateAsMillisecs()).toString()+": "+message);
buf.newLine();
buf.close();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
It seems that some kind of buffer or cache is getting filled and prevents communicating with the device.
How can I get rid of the exception?
Update:
Writing to log file never fails even though I'm getting the exception. It only affects communicating with usb device.
You are opening too many files.
Problems I have found:
- You never close logFile
- You open the file in the log function, a static File would be better and could be initialized in a log_init(); function.
Or, make logFile an object variable and initialize it in the constructor.
I think solving these will solve your problem.
Can you not use getFilesDir() to pass the directory path while creating file
public class L {
public static File logFile = new File("sdcard/log.txt");
public synchronized void log(String message){
....
Everytime you call new File you request a file resource from the system. As you keep doing it the system will complain that you opened too many files. To avoid this, request the file only once.
I have successfully compiled ffmpeg for android and have ported it.
I placed
libffmpeg.so in /system/lib directory
ffmpeg executable in /system/bin and /system/xbin directory (i was not sure where to place it). i directly copied ffmpeg executable from source directory (Not sure whether it's a correct way)
Now i am executing commands from android with following code !!
imports *
public class LatestActivity extends Activity {
private Process process;
String command,text;
static {
System.loadLibrary("ffmpeg");
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_latest);
//Execute Command !!
try {
Execute();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void Execute() throws IOException, InterruptedException{
try {
File dir=new File("/system/bin");
String[] cmd= {"ffmpeg","-codecs"};
process=Runtime.getRuntime().exec(cmd,null,dir);
} catch (IOException e) {
// TODO Auto-generated catch block
Log.d("Process IOException starts:",e.getMessage());
e.printStackTrace();
Log.d("System Manual exit !!",e.getMessage());
System.exit(MODE_PRIVATE);
}
BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()),16384);
BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
// read the output from the command
Log.d("Application output: ","Output if any !");
while ((text = stdInput.readLine()) != null) {
Log.d("Output: ",text); //$NON-NLS-1$
}
text="";
// read any errors from the attempted command
Log.d("Application output: ","Errors if any !"); //$NON-NLS-1$
while ((text = stdError.readLine()) != null) {
Log.d("Error: ",text); //$NON-NLS-1$
}
stdInput.close();
stdError.close();
process.waitFor();
process.getOutputStream().close();
process.getInputStream().close();
process.getErrorStream().close();
destroyProcess(process);
//process.destroy();
}
private static void destroyProcess(Process process) {
try {
if (process != null) {
// use exitValue() to determine if process is still running.
process.exitValue();
}
} catch (IllegalThreadStateException e) {
// process is still running, kill it.
process.destroy();
}
}
}
And Here is the logcat output:
09-05 15:29:13.287: D/dalvikvm(2670): No JNI_OnLoad found in /system/lib/libffmpeg.so 0x44e7e910, skipping init
09-05 15:29:29.117: I/global(2670): Default buffer size used in BufferedReader constructor. It would be better to be explicit if an 8k-char buffer is required.
09-05 15:29:29.117: D/Application output:(2670): Output if any !
09-05 15:29:29.117: D/Application output:(2670): Errors if any !
09-05 15:29:29.127: D/Error:(2670): /system/bin/ffmpeg: 1: Syntax error: "(" unexpected
m neither getting any errors nor output of command. At the end it shows syntax error. I want to know what kind of syntax error it is. how to tackle it?
m i doing something wrong?
This Error occurs if the ffmpeg file does not compiled for your cpu architechture.
Your commands might be right but you need to find correct ffmpeg file.
FIXED
#Gaganpreet Singh
You are right after so much research on this, I have got to know that CPU Chip-set matters too, FFMPEG commands doesn't support INTEL ATOM processor.
Asus Memo Pad 7 using INTEL ATOM cpu chip-set and when trying running ffmpeg command on it, it crashes and throw error "SYNTAX ERROR"
My commands working perfectly on all the devices except the device using INTEL ATOM chipset.
Please review this and this link if it will be helpful for you.
If anyone finds a solution. Please share with us.
Finally Fixed this issue by creating ffmpeg lib for x64 & armv7 using NDK. And used this Library in my Andriod project. Now I have 2 lib and using this lib for different Android CPU ARCH.
Please check this link too. Very helpful.
I am having a hard time figuring out how to write to and read from files on an Android device. The file will be formatted as XML and I already have parsers and data structures built that can format the XML into objects and objects into XML, but the last hurdle is reading the XML from a non-resource file (I know the data structures work because I it works when reading from a resource file) and also writing to a non-resource file. I am terrible at using tools to debug (not sure how to print a stack trace) but I know for a fact the problem is that I cannot read from or write to this files. I have no experience writing to files in Java which may be why I am having a rough time with this.
Write code:
File scoresFile = new File(getExternalFilesDir(null), "scores.xml");
if (!scoresFile.exists())
{
scoresFile.createNewFile();
}
OutputStream os = new FileOutputStream(scoresFile);
os.write(writer.toString().getBytes());
os.flush();
os.close();
Read Code:
XmlPullParserFactory xmlFac = XmlPullParserFactory.newInstance();
XmlPullParser qXML = xmlFac.newPullParser();
InputStream is = null;
File scoresFile = new File(c.getExternalFilesDir(null), "scores.xml");
if (!scoresFile.exists())
{
try {
scoresFile.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
is = new FileInputStream(scoresFile);
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
if (is != null)
qXML.setInput(is,null);
else
qXML = c.getResources().getXml(R.xml.scores);
UPDATE: The last if clause in the read section always evaluates to false. So, the InputStream is null... that appears to be the root of my problem.
I would take a look at these two links: Using Internal Storage and Using External Storage
Both link to the same page, just different portions. Really, it depends on whether or not you want to save this file to the devices memory, or to an external medium (such as an SDcard).
Internal - Sandboxed, so that only your app can access it.
External - Anyone can access it.