I have to read the logs from Logcat and send them to a server through UDP.
For this task I have used this code: https://github.com/chemik/logcatudp
The main problem of that code is that the async Thread that is launched enters a while(true) loop that drains the tablet's battery on the long run.
Is there a way to get the logs in real time but without using a busy wait like that? Hopefully without adding some sleep(some_milliseconds) to reduce the problem?
It would be great to use some sort of event listener but I haven't found one. I have searched in every similar library but without any success.
The code is the following:
while (true) {
String sendingLine = "";
// assume that log writes whole lines
if (bufferedReader.ready()) {
logLine = bufferedReader.readLine();
sendingLine += logLine + System.getProperty("line.separator");
DatagramPacket packet = new DatagramPacket(sendingLine.getBytes(), sendingLine.length(),
InetAddress.getByName(mConfig.mDestServer), mConfig.mDestPort);
try {
mSocket.send(packet);
...
Any idea? Thanks.
Finally the answer was to put a Thread.sleep(10) in the while(true) loop.
It may seem really strange, but also with only 10ms of sleep it reduces the battery usage from almost 40% to 1%.
Related
I seem to be having a small problem with MulticastSocket on Android: writing an SSDP-related application. The socket works just fine when I set everything up the first time, but when I stop discovery, and try to restart things, I just get a SocketException: Socket Closed. I'm not closing the socket, I'm simply stopping the Kotlin Coroutine that is responsible for calling socket.receive() in a loop. Example:
fun listenForPackets(): Flow<DatagramPacket> {
return flow {
multicastSocket.use {
val incomingBuffer = ByteArray(MULTICAST_DATAGRAM_SIZE)
while (true) {
val incomingPacket = DatagramPacket(incomingBuffer, incomingBuffer.size)
it.receive(incomingPacket)
emit(incomingPacket)
incomingPacket.length = incomingBuffer.size
}
}
}
}
The problem
So the problem is that when I try to call that function again, I get a SocketException: Socket Closed. The socket initialization code is run once, meaning that toggling discovery on/off will use the same socket multiple times; the following code is run once throughout the whole application:
multicastSocket = MulticastSocket(MULTICAST_PORT)
multicastSocket.reuseAddress = true
multicastSocket.joinGroup(multicastGroup)
multicastLock.acquire()
What I have tried
My first thought was that I was not cancelling the Kotlin Coroutine correctly. As a result, I switched to using typical Java Threads, to no avail. Starting the thread the first time works, but, restarting discovery yields the same problem. I have also tried to not leave the group, and keep the multicastLock acquired - same problem.
What works
What works is having the initialization code (where I assign the socket, join the group, and acquire lock) run every time I need to start a scan. At the end of the scan, I reset all of the variables (leave group, release lock, close socket). So my question becomes - is this the correct approach? Or am I simply doing something else wrong?
Just to re-iterate, I'm discovering packets just fine, the issue is with restarting the discovery. Thank you in advance for any help!
I have android platform on one end and arduino on the other, connected via serial. Everything works fine, however in some cases arduino restarts itself and causes a flow of unknown characters while its restarting to the serial.
Here is a serial log while arduino is rebooting:
�z������"&O�Z&���B
���F ���cd�:{����t�>��+������2�~����. ���r���DD���^��.�.B�.��ڮ2t��Z:��,R��A�ڢr��Ckˡ���.-���N^���b�����^���
Question is, how can I check on android end if the response was malformed?
You should probably add some kind of "framing" to your messages. CR/LF isn't enough.
For example, put a special "preamble" at the front, and watch for it on the Android side. Choose something that will not occur in the body ("payload") of the message. And choose something that is very unlikely to occur in the random chars that show up on a reboot, a couple of chars long.
You could also put a CRC at the end. "Fletcher" is easy.
I ended up using simple solution like this:
private String filterData(String receivedStr) {
if (receivedStr.contains(RECV_HEADER) && receivedStr.contains(mReadRules.RECV_END)) {
int header_pos = receivedStr.indexOf(RECV_HEADER);
int crc_pos = receivedStr.indexOf(RECV_END);
return receivedStr.substring(header_pos, crc_pos);
} else {
return null;
}
}
It also extracts message if its wrapped around with malformed data.
I need to reproduce Application Not Responding (ANR) dialogs from Activity and from BroadCastReceiver.
I tried to create a simple button click:
public void makeANRClick(View view){
while (true);
}
With this code I reproduced ANR on emulator with android 2.3.7. Same code doesn't work on real device with the newest android versions (4+).
Another attempt was as follows:
public void onMakeANRClick(View view){
try {
Thread.sleep(15000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
This doesn't help also.
Any suggestions?
Keyword multi threading. Please read this topic http://developer.android.com/training/articles/perf-anr.html
Also there is no way to manage UI components at Broadcast Reciever, Because it is no UI component.
Also there is option in Development Options called "Show All ANR"
Have a look at StrictMode. And this video, too.
"StrictMode is a developer tool which detects things you might be doing by accident and brings them to your attention so you can fix them. "
Also you can check the dump state to check info about your process
https://source.android.com/devices/input/diagnostics.html
I reproduce your code and then pull the 'dumpstate_app_anr.txt.gz'
and this was the result
PID TID PR CPU% S VSS RSS PCY UID Thread Proc
15287 15287 0 83% R 227152K 25152K fg u0_a135 a.stackoverflow mx.syca.stackoverflow
07-03 08:46:12.454 1618 1636 I ActivityManager: Killing proc 12946:mx.syca.stackoverflow/u0a135: force stop
It took about 2 minutes to get the ANR dialog
Hope it helps
I do believe that the best way to perform ANR in java (dalvik) is to perform absurd ammount of calculations, including function calls.
Perhaps something akin to:
Integer useless = 0;
for (i=2147483648;i<2147483647;i++){
useless = Math.random() * Math.random() * Math.random() * Math.random();
}
This will at least, trigger some delay, and ANR on weaker systems.
I already know how to stop thread but my present scenario is somewhat different, I am listening for data from server in thread
while (connected)
{
byte[] buffer = new byte[1024];
if(in.read(buffer) > 0)// waits on this line
{
//do something
}
}
now the problem is that although I set connected = false; then also it not stopping because it waits on in.read so , I also tried to Thread.interrupt but no luck
You should probably switch to using a SelectableChannel approach to reading/writing to sockets where non-blocking I/O is used and you can manage multiple connections by listening for 'events'. You then avoid being blocked in calls like read().
This, unfortunetly, is a fundamentally different model to the one you are currently using, so the switch over won't be quick or easy, but it will be worth the effort.
Check out these resources:
http://developer.android.com/reference/java/nio/channels/SocketChannel.html
http://www.exampledepot.com/egs/java.nio/NbClientSocket.html
We need a little more info here:
How do you declare and modify connected?
Do you have a try-catch that is "eating" the InterruptedException?
How do you create the thread?
How are you starting the thread?
How do you (attempt to) terminate the thread?
Provide a sscce compliant example which we can copy & paste, compile and see your exact problem.
In general your code should look like this:
while (connected)
{
try
{
byte[] buffer = new byte[1024];
if(in.read(buffer) > 0)// waits on this line
{
//do something
}
}
catch(InterruptedException ie)
{
// there are several ways which you can exit the loop:
// 1. you can break
// 2. set the connected flag to false
}
}
Verify that you are actually catching the interrupt exception! If you're not catching it, then built a small sscce compliant example in which you're only reproducing the specific issue (should be pretty easy to do).
I modified the code in following way
while (connected)
{
byte[] buffer = new byte[1024];
if(in.available() > 0)// changed this line
{
in.read(buffer)
//do something
}
}
and it worked fine for me since in.available() statement is non- blocking I suppose
I'm developping my first Android App. I need to execute a command in a shell as the root user so I've introduced this code in my App:
process = Runtime.getRuntime().exec("su");
Then I obtain an output stream to the process and I use it to execute the command:
os = new DataOutputStream(process.getOutputStream());
os.writeBytes("tcpdump\n");
Then I obtain an input stream which I want to use for displaying the results of the process:
is = new DataInputStream(process.getInputStream());
I would like to bind the obtained DataInputStream to a TextView in the layout so the text that it displays gets updated in real time as the process goes on showing results.
I've been searching trought the java.io API for android and I can't find an easy way to do this. I've been thinking in running a thread with a loop which continously checks if there is new data in the input stream and then copy it to the TextView but this seems a crappy solution.
I would thank you if anyone knows a way to do this.
Channel channel = session.openChannel("shell");
OutputStream os = new OutputStream() {
#Override
public void write(int oneByte) throws IOException {
TextView textView1 = (TextView) findViewById(R.id.textView1);
char ch = new Character((char) oneByte);
textView1.setText(textView1.getText() + String.valueOf(ch));
System.out.write(oneByte);
}
};
// channel.setOutputStream(System.out);
channel.setOutputStream(os, true);
Combine TextView.append method with Handler
Here is good example:
http://android-developers.blogspot.com/2007/11/stitch-in-time.html
I've been able to set a Handler and start a runnable which will read from the input stream every 200ms.
Despite this, it seems that the input stream isn't receiving any characters form the process standard output and everytime I call a read() method it gets blocked waiting for characters that never come. I've been trying following this two websites instructions without sucess:
http://gimite.net/en/index.php?Run%20native%20executable%20in%20Android%20App
http://code.google.com/p/market-enabler/wiki/ShellCommands
Thanks.
After one day of research and tests, I found that the only solution for this problem is using AsyncTask.
You can adapt this code, which is working fine: https://stackoverflow.com/a/9063257
It also works replacing ProcessBuilder() with Runtime.getRuntime() if you like it.